@DATABASE Libraries Manual
@NODE MAIN "Amiga RKM Libraries: 12 Boopsi--Object Oriented Intuition"
@INDEX Lib_Index/MAIN
@TOC Libraries_Manual/User
Boopsi is an acronym for Basic Object Oriented Programming System for
Intuition.  Using the Object Oriented Programming (OOP) model, Boopsi
represents certain Intuition entities, like @{"Gadget" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9}s and @{"Image" link ADCD_v1.2:Reference_Library/Libraries/Lib_8/8-2-1}s, as objects.

There are many advantages to using Boopsi:

  * Boopsi makes Intuition customizable and extensible.  Boopsi
    programmers can create new types of Boopsi objects to suit the needs
    of their applications.  These new types of objects are part of
    Intuition and can be made public so other applications can use them.
    Because applications can share the new types, application writers
    don't have to waste their time duplicating each other's efforts
    writing the same objects.

  * New types of Boopsi objects can build on old types of Boopsi objects,
    inheriting the old object's behavior.  The result is that Boopsi
    programmers don't have to waste their time building new objects from
    scratch, they simply add to the existing object.

  * OOP and Boopsi apply the concept of interchangeable parts to
    Intuition programming.  A Boopsi programmer can combine different
    Boopsi objects (like gadgets and images) to create an entire
    Graphical User Interface (GUI).  The Boopsi programmer doesn't have
    take the time to understand or implement the inner workings of these
    objects.  The Boopsi programmer only needs to know how to interact
    with Boopsi objects and how to make them interact with each other.

  * Boopsi objects have a consistent, command-driven interface.  To the
    Boopsi programmer, there is no difference between displaying a text,
    border, or bitmap-based Boopsi image, even though they are rendered
    quite differently.  Each image object accepts a single command to
    tell it to render itself.

Before reading this chapter, you should already be familiar with several
Amiga concepts.  Boopsi is built on top of Intuition and uses many of its
structures.  These include Intuition gadgets, images, and windows.  Boopsi
also uses the tag concept  to pass parameters.  The "@{"Utility Library" link ADCD_v1.2:Reference_Library/Libraries/Lib_37/MAIN}"
chapter of this manual discusses @{"tags" link ADCD_v1.2:Reference_Library/Libraries/Lib_37/37-1}.  The "Utility Library" chapter also
discusses @{"callback Hooks" link ADCD_v1.2:Reference_Library/Libraries/Lib_37/37-2}, which are important to the later sections of
this chapter.

@{" OOP Overview " link 12-1}             @{" Boopsi Gadgets " link 12-3}
@{" Creating a Boopsi Class " link 12-2}  @{" Function Reference " link 12-4}

@ENDNODE

@NODE 12-1 "12 Boopsi--Object Oriented Intuition / OOP Overview"
Understanding Boopsi requires an understanding of several of the concepts
behind Object Oriented Programming.  This section is a general overview of
these concepts as they pertain to Boopsi.  Because Boopsi is in part based
on the concepts present in the OOP language Smalltalk, a reference book on
Smalltalk may provide a deeper understanding of Boopsi in general.
Timothy Budd's book entitled A Little Smalltalk (Addison-Wesley Publishing
ISBN 0-201-10698-1) is a good start.

In the Boopsi version of the Object Oriented Programming model, everything
is an Object.  For example, a proportional gadget named myprop is an
object.  Certain objects have similar characteristics and can be
classified into groups called classes.  As objects, Rover the dog, Bob the
cat, and Sam the bird are all distinct objects but they all have something
in common, they can all be classified as animals.  As objects, myprop the
proportional gadget, mystring the string gadget, and mybutton the button
gadget all have something in common, they can all be classified as
gadgets.  A specific object is an instance of a particular class ("Rover"
is an instance of class "animal", "myslidergadget" is an instance of class
"gadget").

Notice that, although Rover, Bob, and Sam can all be classified as
animals, each belongs to a subgroup of the animal class.  "Rover" is an
instance of class "dog", "Bob" is an instance of class "cat", and "Sam" is
an instance of class "bird".  Because each of these animal types share
common characteristics, each type makes up its own class.  Because dog,
cat, and bird are subclassifications of the animal class, they are known
as subclasses of the animal class.  Conversely, the animal class is the
superclass of the dog, cat, and bird classes.

Following the branches upward from class to superclass will bring you to a
universal root category from which all objects are derived.  The OOP
language Smalltalk calls this class "Object".


                  Figure 12-1: Object Diagram


                            object
                               |
                    ___________|__________
                   /                      \
                  /                        \
               animal                  vegetables
                 |                          |
            _____|_____                _____|_____
           /     |     \              /     |     \
          /      |      \            /      |      \
        dog     cat    mouse       peas    corn  spinach


Like Smalltalk, Boopsi also has a universal root catagory, @{"rootclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-2}.
Currently, Intuition defines three immediate subclasses of rootclass.  The
first, @{"gadgetclass" link 12-1-2-2}, is the class of Boopsi gadgets.  The second class,
@{"imageclass" link 12-1-2-1}, makes up the class of Boopsi images.

Unlike @{"gadgetclass" link 12-1-2-2} and @{"imageclass" link 12-1-2-1}, the remaining subclass, @{"icclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-3}, does
not correspond to an existing Intuition entity, it is a concept new to
Intuition.  Icclass, or interconnection class, allows one Boopsi object to
notify another Boopsi object when a specific event occurs.  For example,
consider a Boopsi proportional gadget and a Boopsi image object that
displays an integer value.  An application can connect these two objects
so that the prop gadget tells the image object the prop gadget's current
value, which the image object displays.  Every time the user slides the
prop gadget, the prop gadget notifies the image of the change and the
image updates its display to reflect the prop gadget's current integer
value.  Because these objects are talking to each other rather than the
application, the updates happen automatically.  The application doesn't
have to talk to the two objects, it only has to connect them.

    @{" Figure 12-2: Simple Boopsi Diagram " link "ADCD_v1.2:Reference_Library/lib_pics/12-2.iff/Main"}

An object's characteristics and behavior are determined by its class. Each
class can define a set of attributes and a set of methods that apply to
all objects of that class.  An attribute is a variable characteristic of
an object.  For example, an attribute for the animal class could be the
number of legs an animal object has.  An example of a Boopsi attribute is
the X coordinate of a Boopsi image object.  The data that makes up the
values of an object's attributes is collectively known as the instance
data for that object.

The behavior of an object depends upon the set of methods associated to it
by its class.  A method is basically a function that applies to objects of
that class.  An example of a Boopsi method is the @{"imageclass" link 12-1-2-1} method
@{"IM_DRAW" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-5-1}.  This method tells a Boopsi image to draw itself.  All Boopsi
actions are carried out via methods.

From the Object Diagram, two of the methods of the "animal" class could be
"eat" and "sleep".  One of the methods of the "dog" class could be "bark".
Notice that instances of the "dog" class can do more than just bark, they
can also eat and sleep. This is because a subclass inherits methods from
its superclasses. If there were a subclass of dog called "attack dog", all
instances of that class would be able to bark, eat, and sleep, as well as
"attack".  Due to inheritance, a subclass has all of the methods and all
of the attributes of its superclass.  For example, the @{"IA_Height" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-5-11} attribute
is defined by @{"imageclass" link 12-1-2-1}.  All instances of the subclasses of imageclass
have their own IA_Height attribute, even though the subclasses do not
explicitly define IA_Height.  In turn, all instances of subclasses of the
imageclass subclasses also inherit the IA_Height attribute.  All classes
on levels below a class will inherit its methods and attributes.

When an application or a Boopsi object wants another Boopsi object to
perform a method, it passes it a command in the form of a Boopsi message.
A Boopsi message tells an object which method to perform.  The message may
also contain some parameters that the method requires.

    Watch Out!
    ----------
    The term "message" used in object oriented terminology can be little
    confusing to the Amiga programmer because the Boopsi message has
    nothing to do with an Exec message.

Boopsi classes can be either public or private.  Public classes have ASCII
names associated with them and are accessible to all applications.
Private classes have no ASCII name and normally can only be accessed by
the application that created the private class.

@{" Using Boopsi " link 12-1-1}
@{" The Public Classes " link 12-1-2}
@{" Making Gadget Objects Talk to Each Other " link 12-1-3}
@{" Making Gadgets Talk to an Application " link 12-1-4}
@{" The Interconnection Classes " link 12-1-5}

@ENDNODE

@NODE 12-1-1 "12 / OOP Overview / Using Boopsi"
There are several levels on which a programmer can use Boopsi.  The most
elementary level is to use Intuition functions to create and manipulate
Boopsi objects that are instances of existing, public classes.

At present there is a hierarchy of 14 public classes built into Intuition:


                        Figure 12-3: Class Diagram


                            @{"rootclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-2}
                               /
                 _____________/____________
                /         /                \
               /         /                  \
           @{"icclass" link 12-1 55}      /                @{"gadgetclass" link 12-1-2-2}
             /         /                      \
            /         /         _______________\___________________
           /     @{"imageclass" link 12-1-2-1}    /           /         \             \
          /         /         /           /           \             \
     @{"modelclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-4}    /      @{"propgclass" link 12-1-2-2 4}  @{"strgclass" link 12-1-2-2 7}  @{"buttongclass" link 12-1-2-2 14}  @{"groupgclass" link 12-1-2-2 10}
                  /                                     \
                 /                                       \
         _______/___________________________        @{"frbuttongclass" link 12-1-2-2 20}
        /         \            \            \
       /           \            \            \
  @{"frameiclass" link 12-1-2-1 4}  @{"sysiclass" link 12-1-2-1 9}  @{"fillrectclass" link 12-1-2-1 13}  @{"itexticlass" link 12-1-2-1 16}


@{" Boopsi and Tags " link 12-1-1-1}
@{" Creating an Object " link 12-1-1-2}
@{" Disposing of an Object " link 12-1-1-3}
@{" Setting an Existing Object's Attributes " link 12-1-1-4}
@{" Getting an Object's Attributes " link 12-1-1-5}
@{" What About the Boopsi Messages and Methods? " link 12-1-1-6}

@ENDNODE

@NODE 12-1-1-1 "12 / / Using Boopsi / Boopsi and Tags"
Boopsi uses tag lists to pass and manipulate its attributes.  To Boopsi,
each @{"TagItem" link ADCD_v1.2:Reference_Library/Libraries/Lib_37/37-1-1} (defined in <utility/@{"tagitem.h" link ADCD_v1.2:Inc&AD2.1/includes/utility/tagitem.h/MAIN 21}>) in a tag list is an
attribute/value pair.  The TagItem.ti_Tag field contains an ID for the
attribute and the ti_Data field holds the attribute's value.

For example, the string gadget class defines an attribute called
@{"STRINGA_LongVal" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-12-2}, which is the current integer value of the gadget. Certain
@{"gadgetclass" link 12-1-2-2} objects have an attribute called GA_Image.  Its value is not
an integer, it is a pointer to an image.

Note that these tag lists can also contain utility.library Global System
control tags (like @{"TAG_SKIP" link ADCD_v1.2:Reference_Library/Libraries/Lib_37/37-1-2 8} and @{"TAG_DONE" link ADCD_v1.2:Reference_Library/Libraries/Lib_37/37-1-2 8}), which Boopsi uses in processing
its tag lists.  Any application that ends up processing these lists should
do so using the tag manipulation functions from utility.library.  For more
information on tags and utility.library, see the "@{"Utility Library" link ADCD_v1.2:Reference_Library/Libraries/Lib_37/MAIN}" chapter
of this manual.

@ENDNODE

@NODE 12-1-1-2 "12 / / Using Boopsi / Creating an Object"
The Intuition function @{"NewObjectA()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/NewObject()} creates a Boopsi object:

    mynewobject = APTR NewObjectA(Class *privclass, UBYTE *pubclass,
                                  struct TagItem *myattrs)

The pointer that @{"NewObjectA()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/NewObject()} returns is a pointer to a Boopsi object.  In
general, Boopsi objects are "black boxes".  This means the inner workings
of Boopsi objects are not visible to the application programmer, so the
programmer does not know what goes on inside it.  This really means the
inner workings of these objects are none of your business.  Unless
otherwise documented, only use an object pointer as a handle to the object.

To create an object, @{"NewObjectA()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/NewObject()} needs to know what class the new object
is an instance of.  To create a public class object, pass a NULL pointer
in privclass and an ASCII string in pubclass naming the object's public
class.  The privclass pointer is used to create a private class object,
which is covered in the "@{"Creating a Boopsi Class" link 12-2-2-4}" section later in this
chapter.

The myattrs tag list is a list of tag/value pairs, each of which contains
an initial value for some object attribute.  Most objects have a set of
attributes associated with them, so each attribute has a tag name.  For
Boopsi gadgets and images, the attributes include some of the values from
the old @{"Gadget" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9} and @{"Image" link ADCD_v1.2:Reference_Library/Libraries/Lib_8/8-2-1} structures (position, size, etc.).

Most applications use the stack-based version of @{"NewObjectA()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/NewObject()},
@{"NewObject()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/NewObject()}, to create objects.  This allows an application to build the
tag list of object attributes on the stack rather than having to allocate
and initialize a tag list.  A code sample from a program that creates a
Boopsi string gadget might look like this:

    mystringgadget = (struct Gadget *)NewObject(NULL, "strgclass",
                                                GA_ID,           1L,
                                                GA_Left,         0L,
                                                GA_Top,          0L,
                                                STRINGA_LongVal, 100L,
                                                TAG_END);

If @{"NewObject()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/NewObject()} is successful, it returns a pointer to a new Boopsi gadget
object.  Otherwise, it returns NULL.  The class "@{"strgclass" link 12-1-2-2 7}" is one of the
public classes built into Release 2.  It is a class of string gadgets.

If you look at the diagram of the public classes built into Intuition,
you'll see that @{"strgclass" link 12-1-2-2 7} is a subclass of @{"gadgetclass" link 12-1-2-2}. In the example
above, the attribute tag IDs that start with "GA_" are defined by
gadgetclass and not by strgclass.  This is because strgclass inherits
these attributes from its superclass, gadgetclass. The other attribute,
@{"STRINGA_LongVal" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-12-2}, is defined by strgclass.  It does two things.  First, it
tells the object that it is a special type of string gadget which only
handles an integer value rather than a generic ASCII string.  Second, it
passes the object its initial integer value.

@ENDNODE

@NODE 12-1-1-3 "12 / / Using Boopsi / Disposing of an Object"
When an application is done with an object it has to dispose of the
object.  To dispose of an object, use the Intuition function
@{"DisposeObject()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/DisposeObject()}:

    VOID DisposeObject(APTR boopsiobject);

where boopsiobject is a pointer to the Boopsi object to be disposed.  Note
that some classes allow applications to connect child objects to a parent
object so that when the application deletes the parent object, it
automatically disposes of all of its children.  Be careful not to dispose
of an object that has already been disposed.

@ENDNODE

@NODE 12-1-1-4 "12 / / Using Boopsi / Setting an Existing Object's Attributes"
An object's attributes are not necessarily static.  An application can ask
an object to set certain object attributes using the @{"SetAttrs()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/SetAttrsA()} function:

    ULONG SetAttrs(APTR myobject, Tag1, Value1, ...);

Because Boopsi gadgets require some extra information about their display,
they use a special version of this function, @{"SetGadgetAttrs()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/SetGadgetAttrsA()}:

    ULONG SetGadgetAttrs(struct Gadget *myobject, struct Window *w,
                         struct Requester *r, Tag1, Value1, ...);

Here myobject is a pointer to the Boopsi object, w points to the gadget's
window, r points to the gadget's requester, and the tag/value pairs are
the attributes and their new values.  The return value of @{"SetAttrs()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/SetAttrsA()} and
@{"SetGadgetAttrs()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/SetGadgetAttrsA()} is class specific.  In general, if the attribute change
causes a visual change to some object, the SetAttrs()/SetGadgetAttrs()
function should return a non-zero value, otherwise, these functions should
return zero (see the Boopsi Class Reference in "@{"Appendix B" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/MAIN}" of this manual
for information on the return values for specific classes).  The following
is an example of how to set the current integer value and gadget ID of the
gadget created in the @{"NewObject()" link 12-1-1-2 25} call above:

    SetGadgetAttrs(mystringgadget, mywindow, NULL, STRINGA_LongVal,   75L,
                                                   GA_ID,             2L,
                                                   TAG_END));

This changes two of mystringgadget's attributes.  It changes the gadget's
current integer value to 75 and it changes the gadget's ID number to 2.

Note that it is not OK to call @{"SetGadgetAttrs()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/SetGadgetAttrsA()} on a Boopsi object that
isn't a gadget, nor is it OK to call @{"SetAttrs()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/SetAttrsA()} on a Boopsi gadget.

Not all object attributes can be set with @{"SetGadgetAttrs()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/SetGadgetAttrsA()}/@{"SetAttrs()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/SetAttrsA()}.
Some classes are set up so that applications cannot change certain
attributes.  For example, the imagery for the knob of a proportional
gadget cannot be altered after the object has been created.  Whether or
not a specific attribute is "settable" is class dependent.  For more
information about the attributes of specific classes, see the Boopsi Class
Reference in the @{"Appendix B" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/MAIN} of this manual.

@ENDNODE

@NODE 12-1-1-5 "12 / / Using Boopsi / Getting an Object's Attributes"
The Intuition function @{"GetAttr()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/GetAttr()} asks an object what the value of a
specific attribute is:

    ULONG GetAttr(ULONG attrID, APTR myobject, ULONG *mydata);

where attrID is the attribute's ID number, myobject is the object to get
the attribute from, and mydata points to a data area that will hold the
attribute value.  This function returns a 0L if the object doesn't
recognize the attribute, otherwise it returns some non-zero value, the
meaning of which depends on the class.  In most cases, @{"GetAttr()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/GetAttr()} returns a
1 when it is successful.

Not all object attributes are obtainable using the @{"GetAttr()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/GetAttr()} function.
Some classes are set up so that applications cannot query the state of
certain attributes.  For example, using the @{"GA_Image" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-11-2} attribute, an
application can give a Boopsi prop gadget (@{"propgclass" link 12-1-2-2 4}) an @{"Image" link ADCD_v1.2:Reference_Library/Libraries/Lib_8/8-2-1} structure
which the gadget uses as the imagery for its knob. This attribute is not
"gettable" as there is no need for an application to have to ask the
gadget for the structure that the application passed it in the first
place.  Whether or not a specific attribute is "gettable" is class
dependent.  For more information about the attributes of specific classes,
see the Boopsi Class Reference in the @{"Appendix B" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/MAIN} of this manual.

@ENDNODE

@NODE 12-1-1-6 "12 / / Using Boopsi / What About the Boopsi Messages and Methods?"
According to the "@{"OOP Overview" link 12-1 100}" section, for an object to perform a
method, something has to pass it a Boopsi message.  The previous section
discussed using Intuition functions to ask an object to do things like set
and get attributes.  The functions in the previous section seem to
completely ignore all that material about methods and messages.  What
happened to the methods and messages?

Nothing--these functions don't ignore the OOP constructs, they just shield
the programmer from them.  Each of these functions corresponds to a Boopsi
method:

    @{"NewObject()" link 12-1-1-2 25}                  @{"OM_NEW" link 12-2-2 20}
    @{"DisposeObject()" link 12-1-1-3}              @{"OM_DISPOSE" link 12-2-2 24}
    @{"SetAttrs()/SetGadgetAttrs()" link 12-1-1-4}  @{"OM_SET" link 12-2-2 28}
    @{"GetAttr()" link 12-1-1-5}                    @{"OM_GET" link 12-2-2 36}

These methods are defined on the @{"rootclass" link 12-1 50} level, so all Boopsi classes
inherit them.  The Intuition functions that correspond to these methods
take care of constructing and sending a Boopsi message with the
appropriate method ID and parameters.

@ENDNODE

@NODE 12-1-2 "12 / OOPOverview / The Public Classes"
Intuition contains 14 public classes, all of which are descendants of the
@{"rootclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-2}.  There are three primary classes that descend directly from
rootclass: imageclass, gadgetclass, and @{"icclass" link 12-1 55}.

@{" The Imageclass Subclasses " link 12-1-2-1}  @{" The Gadgetclass Subclasses " link 12-1-2-2}

@ENDNODE

@NODE 12-1-2-1 "12 / / The Public Classes / The Imageclass Subclasses"
Normally, an application does not create an @{"imageclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-5} object. Instead, it
will use a subclass of imageclass.  Currently, there are four subclasses:
frameiclass, sysiclass, fillrectclass, and itexticlass.

@{"frameiclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-6}
    An embossed or recessed rectangular frame image, that renders itself
    using the proper @{"DrawInfo" link ADCD_v1.2:Reference_Library/Libraries/Lib_3/3-2-2 6} pens.  This class is intelligent enough to
    bound or center its contents.

@{"sysiclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-7}
    The class of system images.  The class includes the images for the
    system and GadTools gadgets.

@{"fillrectclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-8}
    A class of rectangle images that have frame and patternfill support.

@{"itexticlass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-9}
    A specialized image class used for rendering text.

For more information on these classes see the Boopsi Class Reference in
the @{"Appendix B" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/MAIN} of this manual.  It describes all of the existing public
classes, their methods, and their attributes.

@{" The Gadgetclass Subclasses " link 12-1-2-1}

@ENDNODE

@NODE 12-1-2-2 "12 / / The Public Classes / The Gadgetclass Subclasses"
Like @{"imageclass" link 12-1-2-1}, applications do not normally create objects of
@{"gadgetclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-10}, but instead create objects of its subclasses. Currently,
gadgetclass has four subclasses:

@{"propgclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-11}
    An easy to implement, horizontal or vertical proportional gadget.

@{"strgclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-12}
    A string gadget.

@{"groupgclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-15}
    A special gadget class that creates one composite gadget out of
    several others.

@{"buttongclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-13}
    A button gadget that keeps sending button presses while the user
    holds it down.

buttongclass has a subclass of its own:

@{"frbuttonclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-14}
    A buttongclass gadget that outlines its imagery with a frame.

For specific information on these classes, see the Boopsi Class Reference
in the @{"Appendix B" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/MAIN} of this manual.

@ENDNODE

@NODE 12-1-3 "12 / OOP Overview / Making Gadget Objects Talk to Each Other"
One use for a proportional gadget is to let the user change some integer
value, like the red, green, and blue components of a color. This type of
prop gadget is commonly accompanied by an integer string gadget, enabling
the user to adjust one integer value by either typing the value into the
string gadget or by scrolling the prop gadget.  Because these two gadgets
reflect the value of the same integer, when the user adjusts the state of
one of the gadgets (and thus changing the integer value), the other gadget
should automatically update to reflect the new integer value.

When the user manipulates a conventional gadget, the gadget sends messages
to an IDCMP port to indicate the state change (for information on IDCMP,
see the "@{"Intuition Input and Output Methods" link ADCD_v1.2:Reference_Library/Libraries/Lib_9/9-5}" chapter of this manual).  To
connect the string and prop gadgets from the previous paragraph, an
application would have to listen for the IDCMP messages from two different
gadgets, interpret the IDCMP message's meaning, and manually update the
gadgets accordingly. Essentially, the application is responsible for
"gluing" the gadgets together.  This unnecessarily complicates an
application, especially when that application already has to listen for
and interpret many other events.

Boopsi gadgets simplify this.  By setting the appropriate attributes, an
application can ask a Boopsi gadget to tell some other object when its
state changes.  One of the attributes defined by @{"gadgetclass" link 12-1-2-2} is @{"ICA_TARGET" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-10-9}
(defined in <intuition/@{"icclass.h" link ADCD_v1.2:Inc&AD2.1/includes/intuition/icclass.h/MAIN 26}>).  The ICA_TARGET attribute points to
another Boopsi object.  When certain attributes in a Boopsi gadget change
(like the integer value of a prop gadget), that gadget looks to see if it
has an ICA_TARGET.  If it does, it sends the target a message telling it
to perform an @{"OM_UPDATE" link 12-2-2 32} method.

The @{"OM_UPDATE" link 12-2-2 32} method is defined by @{"rootclass" link 12-1 50}.  This is basically a special
type of @{"OM_SET" link 12-2-2 28} method that is used specifically to tell a Boopsi object
that another Boopsi object's state changed.  Only Boopsi objects send
OM_UPDATE messages.  Note that standard classes of Boopsi gadgets only
send out OM_UPDATE messages as a result of the user changing the state of
the gadget (scrolling the prop gadget, typing a new number into an integer
gadget, etc.).  These gadgets do not send out OM_UPDATE messages when they
receive OM_SET or OM_UPDATE messages.

A Boopsi @{"propgclass" link 12-1-2-2 4} object has only one attribute that triggers it to send
an @{"OM_UPDATE" link 12-2-2 32} request: @{"PGA_Top" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-11-8}. This attribute contains the integer value
of the prop gadget.  Every time the user moves a prop gadget, the PGA_Top
attribute changes.  If the prop gadget has an @{"ICA_TARGET" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-10-9}, the prop gadget
will tell the target object that the PGA_Top value has changed.

A Boopsi integer string gadget (a @{"strgclass" link 12-1-2-2 7} object) also has only one
attribute that triggers it to send an @{"OM_UPDATE" link 12-2-2 32} request: @{"STRINGA_LongVal" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-12-2}.
value contains the integer value of the integer string gadget.  Like
the prop gadget, if the integer string gadget has an @{"ICA_TARGET" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-10-9}, when the
user changes the gadget's integer value (STRINGA_LongVal), the string
gadget will tell the target object that the STRINGA_LongVal value has
changed.

When a Boopsi gadget sends an @{"OM_UPDATE" link 12-2-2 32} message, it passes the ID of the
attribute that changed plus that attribute's new value.  For example, if
the user typed a 25 into a Boopsi integer string gadget, that gadget would
send an OM_UPDATE message to its @{"ICA_TARGET" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-10-9} saying in essence, "Hey,
@{"STRINGA_LongVal" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-12-2} is 25".

If this string gadget's @{"ICA_TARGET" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-10-9} is a @{"propgclass" link 12-1-2-2 4} object, the propgclass
object will become confused because it has no idea what a @{"STRINGA_LongVal" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-12-2}
attribute is.  The string gadget needs to map its STRINGA_LongVal ID to
the @{"PGA_Top" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-11-8} ID.  This is what the @{"ICA_MAP" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-10-10} attribute is for.

The ICA_MAP attribute is defined by @{"gadgetclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-10-10} (it is also defined for
@{"icclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-3-3}--more on that later).  It accepts a tag list of attribute
mappings.  When a gadget sends out an @{"OM_UPDATE" link 12-2-2 32} message, it uses this map
to translate a specific attribute ID to another attribute ID, without
changing the value of the attribute.  Each @{"TagItem" link ADCD_v1.2:Reference_Library/Libraries/Lib_37/37-1-1} in the ICA_MAP makes up
a single attribute mapping. The TagItem.ti_Tag of the mapping is the ID of
an attribute to translate.  The gadget translates that attribute ID to the
attribute ID in TagItem.ti_Data.  For example, an ICA_MAP that maps a
string gadget's @{"STRINGA_LongVal" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-12-2} attribute to a prop gadget's @{"PGA_Top" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-11-8}
attribute looks like this:

    struct TagItem slidertostring[] = {
        {PGA_Top, STRINGA_LongVal},
        {TAG_END, }
    };

Note that it is OK to have an ICA_TARGET without having an ICA_MAP.  In
cases where a gadget and its @{"ICA_TARGET" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-10-9} have a set of attributes in
common, it would be unnecessary to use an @{"ICA_MAP" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-10-10} to match a gadget's
attributes, as they already match.

The following example, Talk2boopsi.c, creates a prop gadget and an integer
string gadget which update each other without the example program having
to process any messages from them.

    @{" Talk2boopsi.c " link ADCD_v1.2:Reference_Library/Libraries/lib_examples/Talk2boopsi.c/MAIN}

@ENDNODE

@NODE 12-1-4 "12 / OOP Overview / Making Gadgets Talk to an Application"
There are two questions that the @{"example" link ADCD_v1.2:Reference_Library/Libraries/lib_examples/talk2boopsi.c/MAIN} above brings to mind.  The first
is, "What happens if the user types a value into the string gadget that is
beyond the bounds of the prop gadget?"  The answer is simple: very little.
The prop gadget is smart enough to make sure its integer value does not go
beyond the bounds of its display.  In the example, the prop gadget can
only have values from 0 to 90.  If the user tries to type a value greater
than 90, the prop gadget will set itself to its maximum of 90.  Because
the integer string gadget doesn't have any bounds checking built into it,
the example needs to find an alternative way to check the bounds.

The other question is, "How does @{"talk2boopsi.c" link ADCD_v1.2:Reference_Library/Libraries/lib_examples/talk2boopsi.c/MAIN} know the current value of
the gadgets?"  That answer is simple too: it doesn't.  The example doesn't
ask the gadgets what their current values are (which it would do using
@{"GetAttr()" link 12-1-1-5}) and the example doesn't pay attention to gadget events at the
window's IDCMP port, so it isn't going to hear about them.

One easy way to hear about changes to the gadget events is to listen for a
"release verify".  Conventional Intuition gadgets can trigger a release
verify IDCMP event when the user finishes manipulating the gadget.  Boopsi
gadgets can do this, too, while continuing to update each other.

To make @{"Talk2boopsi.c" link ADCD_v1.2:Reference_Library/Libraries/lib_examples/talk2boopsi.c/MAIN} do this would require only a few changes. First, the
window's IDCMP port has to be set up to listen for @{"IDCMP_GADGETUP" link ADCD_v1.2:Reference_Library/Libraries/Lib_9/9-6-1-2 6} events.
Next, the example needs to set the gadget's @{"GACT_RELVERIFY" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9-2 14} flags.  It can
do this by setting the @{"gadgetclass" link 12-1-2-2} @{"GA_RelVerify" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-10-18} attribute to TRUE for both
gadgets.  That's enough to trigger the release verify message, so all
Talk2boopsi.c needs to do is account for the new type of IDCMP message,
IDCMP_GADGETUP.  When Talk2boopsi.c gets a release verify message, it can
use @{"GetAttr()" link 12-1-1-5} to ask the integer gadget its value.  If this value is out
of range, it should explicitly set the value of the integer gadget to a
more suitable value using @{"SetGadgetAttrs()" link 12-1-1-4 5}.

Using the @{"GACT_RELVERIFY" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9-2 14} scheme above, an application will only hear about
changes to the gadgets after the user is finished changing them.  The
application does not hear all of the interim updates that, for example, a
prop gadget generates.  This is useful if an application only needs to
hear the final value and not the interim update.

It is also possible to make the IDCMP port of a Boopsi gadget's window the
@{"ICA_TARGET" link 12-1-3 20} of the gadget.  There is a special value for ICA_TARGET called
ICTARGET_IDCMP (defined in <intuition/@{"icclass.h" link ADCD_v1.2:Inc&AD2.1/includes/intuition/icclass.h/MAIN 35}>). This tells the gadget
to send an @{"IDCMP_IDCMPUPDATE" link ADCD_v1.2:Reference_Library/Libraries/Lib_9/9-6-1-6 98} class @{"IntuiMessage" link ADCD_v1.2:Reference_Library/Libraries/Lib_9/9-5-4} to its window's IDCMP
port.  Of course, the window has to be set up to listen for
IDCMP_IDCMPUPDATE IntuiMessages.  The Boopsi gadget passes an address in
the @{"IntuiMessage.IAddress" link ADCD_v1.2:Reference_Library/Libraries/Lib_9/9-5-4 73} field.  It points to an attribute tag list
containing the attribute (and its new value) that triggered the
IDCMP_IDCMPUPDATE message.  An application can use the utility.library tag
functions to access the gadget's attributes in this list.  Using this
scheme, an application will hear all of the interim gadget updates.  If
the application is using a gadget that generates a lot of interim
@{"OM_UPDATE" link 12-2-2 32} messages (like a prop gadget), the application should be
prepared to handle a lot of messages.

Using this @{"IDCMP_IDCMPUPDATE" link ADCD_v1.2:Reference_Library/Libraries/Lib_9/9-6-1-6 98} scheme, if the gadget uses an @{"ICA_MAP" link 12-1-3 63} to map
the attribute to a special dummy attribute ICSPECIAL_CODE (defined in
<intuition/@{"icclass.h" link ADCD_v1.2:Inc&AD2.1/includes/intuition/icclass.h/MAIN 26}>), the @{"IntuiMessage.Code" link ADCD_v1.2:Reference_Library/Libraries/Lib_9/9-5-4 33} field will contain the value
of the attribute.  Because the attribute's value is a 32-bit quantity and
the IntuiMessage.Code field is only 16 bits wide, only the least
significant 16 bits of the attribute will appear in the IntuiMessage.Code
field, so it can't hold a 32-bit quantity, like a pointer.  Applications
should only use the lower 16 bits of the attribute value.

@ENDNODE

@NODE 12-1-5 "12 / OOP Overview / The Interconnection Classes"
The @{"IDCMP_IDCMPUPDATE" link ADCD_v1.2:Reference_Library/Libraries/Lib_9/9-6-1-6 98} scheme presents a problem to an application that
wants to make gadgets talk to each other and talk to the application.
Boopsi gadgets only have one @{"ICA_TARGET" link 12-1-3 20}.  One Boopsi gadget can talk to
either another Boopsi object or its window's IDCMP port, but not both.
Using this scheme alone would force the application to update the integer
value of the gadgets, which is what we are trying to avoid in the first
place.

One of the standard Boopsi classes, @{"icclass" link 12-1 55}, is a class of information
forwarders.  An icclass object receives @{"OM_UPDATE" link 12-2-2 32} messages from one object
and passes those messages on to its own @{"ICA_TARGET" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-3-3}.  If it needs to map
any incoming attributes, it can use its own @{"ICA_MAP" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-3-4} to do so.

@{"Icclass" link 12-1 55} has a subclass called @{"modelclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-4}.  Using a modelclass object, an
application can chain a series of these objects together to set up a
"broadcast list" of icclass objects.  The modelclass object is similar to
the icclass object in that it has its own @{"ICA_TARGET" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-3-3} and @{"ICA_MAP" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-3-4}.  It
differs in that an application can use the modelclass @{"OM_ADDMEMBER" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-4-1} method
to add icclass objects to the modelclass object's broadcast list.

The @{"OM_ADDMEMBER" link 12-2-2 48} method is defined by @{"rootclass" link 12-1 50}.  It adds one Boopsi
object to the personal list of another Boopsi object.  It is up to the
Boopsi object's class to determine the purpose of the objects in the list.
Unlike the other methods mentioned so far in this chapter, OM_ADDMEMBER
does not have an Intuition function equivalent.  To pass an OM_ADDMEMBER
message to an object use the amiga.lib function @{"DoMethodA()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/DoMethodA()}, or its
stack-based equivalent, @{"DoMethod()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/DoMethod()}:

    ULONG DoMethodA(Object *myobject, Msg boopsimessage);
    ULONG DoMethod(Object *myobject, ULONG methodID, ...);

The return value is class-dependent.  The first argument to both of these
functions points to the object that will receive the Boopsi message.

For @{"DoMethodA()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/DoMethodA()}, boopsimessage is the actual Boopsi message.  The layout
of it depends on the method.  Every method's message starts off with an
Msg (from <intuition/@{"classusr.h" link ADCD_v1.2:Inc&AD2.1/includes/intuition/classusr.h/MAIN 24}>):

    typedef struct {
        ULONG MethodID; /* Method-specific data may follow this field */
    } *Msg;

The message that the @{"OM_ADDMEMBER" link 12-2-2 48} method uses looks like this (from
<intuition/@{"classusr.h" link ADCD_v1.2:Inc&AD2.1/includes/intuition/classusr.h/MAIN 121}>):

    struct opMember {
        ULONG    MethodID;
        Object   *opam_Object;
    };

where MethodID is @{"OM_ADDMEMBER" link 12-2-2 48} and opam_Object points to the object to add
to myobject's list.

@{"DoMethod()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/DoMethod()} uses the stack to build a message.  To use DoMethod(), just
pass the elements of the method's message structure as arguments to
DoMethod() in the order that they appear in the structure.  For example,
to ask the Boopsi object myobject to add the object addobject to its
personal list:

    DoMethod(myobject, OM_ADDMEMBER, addobject);

To rearrange @{"Talk2boopsi.c" link ADCD_v1.2:Reference_Library/Libraries/lib_examples/talk2boopsi.c/MAIN} so that it uses a @{"modelclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-4} object (also known
as a model):

  * Create the integer and prop gadget.

  * Create the model.

  * Create two @{"icclass" link 12-1 55} objects, one called int2prop and the other called
    prop2int.

  * Make the model the @{"ICA_TARGET" link 12-1-3 20} of both the integer gadget and the prop
    gadget.  The gadgets do not need an @{"ICA_MAP" link 12-1-3 63}.

  * Using @{"DoMethod()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/DoMethod()} to call @{"OM_ADDMEMBER" link 12-2-2 48}, add the @{"icclass" link 12-1 55} objects to the
    model's personal list.

  * Make the prop gadget the @{"ICA_TARGET" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-3-3} of int2prop.  Make the integer
    gadget the ICA_TARGET of prop2int.

  * Create an @{"ICA_MAP" link ADCD_v1.2:Reference_Library/Libraries/Lib_C/C-3-4} map list for int2prop that maps @{"STRINGA_LongVal" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-12-2} to
    @{"PGA_Top" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-11-8}.  Create an ICA_MAP map list for prop2int that maps PGA_Top
    to STRINGA_LongVal.  Make the @{"ICA_TARGET" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-3-3} of the model @{"ICTARGET_IDCMP" link 12-1-4 38}.

Diagrammatically, the new @{"Talk2boopsi.c" link ADCD_v1.2:Reference_Library/Libraries/lib_examples/talk2boopsi.c/MAIN} should look something like this:

    @{" Figure 12-4: ICC Diagram " link "ADCD_v1.2:Reference_Library/lib_pics/12-4.iff/Main"}

When either of these gadgets has some interim state change (caused by the
user manipulating the gadgets), it sends an @{"OM_UPDATE" link 12-2-2 32} message to its
@{"ICA_TARGET" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-3-3}, which in this case is the @{"modelclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-4} object.  When this model
gets the message, it does two things.  It sends an @{"IDCMP_IDCMPUPDATE" link ADCD_v1.2:Reference_Library/Libraries/Lib_9/9-6-1-6 98} to
the IDCMP port of the gadget's window and it also sends OM_UPDATE messages
to all of the objects in its personal list.  When int2prop gets an
OM_UPDATE message, it forwards that message to its ICA_TARGET, the prop
gadget.  Similarly, when prop2int gets an OM_UPDATE message, it forwards
that message to its ICA_TARGET, the integer gadget.

Although in this case it isn't a problem, @{"icclass" link 12-1 55} and @{"modelclass" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-4} objects
contain loop inhibition capabilities.  If an icclass object (or modelclass
object) receives an @{"OM_UPDATE" link 12-2-2 32} message, it forwards the message to its
target.  If somehow that forwarded message gets forwarded (or broadcast)
back to the icclass object, the icclass object ignores the message.  This
prevents the possibility of an infinite OM_UPDATE loop.

@ENDNODE

@NODE 12-2 "12 Boopsi--Object Oriented Intuition / Creating a Boopsi Class"
So far this chapter has only hinted at what is possible with Boopsi. Its
power lies in its extensibility.  Boopsi grants the application programmer
the power to add custom features to existing classes.  If an existing
class comes close to your needs, you can build on that class so it does
exactly what you want.  If you want a class that is unlike an existing
class, you can create it.

The heart of a Boopsi class is its method Dispatcher function. According
to the OOP metaphor, when an application wants a Boopsi object to perform
a method, it sends the object a message.  In reality, that object is only
a data structure, so it does not have the power to do anything.  When an
object receives a Boopsi message, a Boopsi message structure is passed to
the dispatcher of that object's class.  The dispatcher examines the
message and figures out what to do about it.

For example, when an application calls @{"SetGadgetAttrs()" link 12-1-1-4 5} on an integer
gadget:

    SetGadgetAttrs(myintegergadget, mywindow, NULL,
                   STRINGA_LongVal, 75L,
                   GA_ID,           2L,
                   TAG_END));

the @{"SetGadgetAttrs()" link 12-1-1-4 5} function calls the @{"strgclass" link 12-1-2-2 7} dispatcher.  A Boopsi
dispatcher receives three arguments: a pointer to the dispatcher's Class
(defined in <intuition/@{"classes.h" link ADCD_v1.2:Inc&AD2.1/includes/intuition/classes.h/MAIN}>), a pointer to the object that is going
to perform the method, and a pointer to the Boopsi message.  In this case,
the SetGadgetAttrs() function builds an @{"OM_SET" link 12-2-2 28} message, finds the
strgclass dispatcher, and "sends" the dispatcher the OM_SET message.
SetGadgetAttrs() can find the dispatcher because an object contains a
reference to its dispatcher.

When the dispatcher function "gets" the message, it examines the message
to find out its corresponding method.  In this case, the dispatcher
recognizes the message as an @{"OM_SET" link 12-2-2 28} message and proceeds to set
myintegergadget's attributes.

An @{"OM_SET" link 12-2-2 28} message looks like this (defined in <intuition/@{"classusr.h" link ADCD_v1.2:Inc&AD2.1/includes/intuition/classusr.h/MAIN 76}>):

    struct opSet {
        ULONG MethodID;               /* This will be set to OM_SET      */
        struct TagItem *ops_AttrList; /* A tag list containing the       */
                                      /*     attribute/value pairs of    */
                                      /*     the attributes to set.      */
        struct GadgetInfo *ops_GInfo; /* Special information for gadgets */
    }

The @{"OM_SET" link 12-2-2 28} message contains a pointer to a tag list in ops_AttrList that
looks like this:

    {STRINGA_LongVal, 75L},
    {GA_ID, 2L},
    {TAG_END,}

The @{"strgclass" link 12-1-2-2 7} dispatcher scans through this tag list and recognizes the
@{"STRINGA_LongVal" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-12-2} attribute.  The dispatcher sets myintegergadget's internal
STRINGA_LongVal value to the corresponding value (75L) from the
attribute/value pair.

The @{"strgclass" link 12-1-2-2 7} dispatcher continues to scan through the tag list.  When it
finds @{"GA_ID" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-10-15}, it does not process it like @{"STRINGA_LongVal" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-12-2}.  The strgclass
dispatcher's @{"OM_SET" link 12-2-2 28} method does not recognize the GA_ID attribute because
strgclass inherited the GA_ID attribute from @{"gadgetclass" link 12-1-2-2}.  To handle
setting the GA_ID attribute, the strgclass dispatcher passes on the OM_SET
message to its superclass's dispatcher.  The strgclass dispatcher passes
control to the gadgetclass dispatcher, which knows about the GA_ID
attribute.

@{" Building On Existing Public Classes " link 12-2-1}
@{" Writing the Dispatcher " link 12-2-2}
@{" White Boxes - The Transparent Base Classes " link 12-2-3}

@ENDNODE

@NODE 12-2-1 "12 / Creating a Boopsi Class / Building On Existing Public Classes"
A program can create its own subclasses which build on the features of
existing classes.  For example, a program could create a subclass of
@{"modelclass" link 12-1-5 13} named rkmmodelclass.  Rkmmodelclass builds on modelclass by
adding a new attribute called RKMMOD_CurrVal.  This purpose of this
attribute is simply to hold an integer value.

Because this new attribute is built into an rkmmodel object, the object
could be implemented so that it exercises a certain amount of control over
that value.  For example, rkmmodelclass could be implemented so an
rkmmodel performs bounds checking on its internal value.  When an
application asks an rkmmodel to set its internal RKMMOD_CurrVal, the
rkmmodel makes sure the new value is not beyond a maximum value.  If the
new value is beyond the maximum, it sets its current value to the maximum.
After the rkmmodelclass object has set its internal RKMMOD_CurrVal, it can
broadcast the change on to objects in its broadcast list.

The dispatcher for rkmmodelclass does not have to do a lot of work because
it inherits most of its behavior from its superclasses.  The rkmmodelclass
has to take care of setting aside memory for the RKMMOD_CurrVal attribute
and processing any @{"OM_SET" link 12-2-2 28} requests to set the RKMMOD_CurrVal attribute.
For any other attributes or methods, the rkmmodelclass dispatcher passes
on processing to its superclass, @{"modelclass" link 12-1-5 13}.

@{" Building Rkmmodelclass " link 12-2-1-1}

@ENDNODE

@NODE 12-2-1-1 "12 / / Building On Existing Public Classes / Building Rkmmodelclass"
So far, the theoretical class @{"rkmmodelclass" link 12-2-1} has just one attribute,
@{"RKMMOD_CurrVal" link 12-2-1}.  A couple of extra attributes can make it more useful.
Because the rkmmodel object maintains an upper limit on its RKMMOD_CurrVal
integer value, it would be useful if that upper limit was variable.  Using
a new attribute, RKMMOD_Limit, an application can tell a rkmmodel what its
upper limit is.  The rkmmodel will enforce the limit internally, so the
application doesn't have to worry about it.

Another useful addition is a pulse increment and decrement for
@{"RKMMOD_CurrVal" link 12-2-1}.  Whenever the model receives an increment or decrement
command, it increments or decrements its internal value. To make the
example class simple, @{"rkmmodelclass" link 12-2-1} implements incrementing and
decrementing by creating "dummy" attributes called RKMMOD_Up and
RKMMOD_Down.  When an rkmmodel receives an @{"OM_SET" link 12-2-2 28} message for one of these
attributes, it increments or decrements RKMMOD_CurrVal.  An rkmmodelclass
object does not care what the value of the RKMMOD_Up and RKMMOD_Down
attributes are, it only cares that it received an @{"OM_UPDATE" link 12-2-2 32} about it.

There are two pieces of data that make up this new class's instance data:
the rkmmodel's current value (@{"RKMMOD_CurrVal" link 12-2-1}) and the upper limit of the
rkmmodel (RKMMOD_Limit).  The example class consolidates them into one
structure:

    struct RKMModData {
        ULONG currval;
        ULONG vallimit;
    };

@ENDNODE

@NODE 12-2-2 "12 / Creating a Boopsi Class / Writing the Dispatcher"
The C prototype for a Boopsi dispatcher looks like this:

    ULONG dispatchRKMModel(Class *cl, Object *recvobject, Msg msg);

where cl points to the Class (defined in <intuition/@{"classes.h" link ADCD_v1.2:Inc&AD2.1/includes/intuition/classes.h/MAIN}>) of the
dispatcher, recvobject points to the object that received the message, and
msg is that Boopsi message.  The format of the message varies according to
the method.  The default Boopsi message is an Msg (from
<intuition/@{"classusr.h" link ADCD_v1.2:Inc&AD2.1/includes/intuition/classusr.h/MAIN 24}>):

    typedef struct {
        ULONG MethodID;
    } *Msg;

Boopsi methods that require parameters use custom message structures. The
first field of any message structure is always the method's methodID.
This makes custom messages look like an Msg.  The dispatcher looks at an
incoming message's first field to tell what its method is.  @{"Rkmmodelclass" link 12-2-1}
objects respond to several @{"rootclass" link 12-1 50} methods:

@{"OM_NEW" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-2-1}
    This method creates a new @{"rkmmodelclass" link 12-2-1} object.  It uses an @{"opSet" link 12-2-2 1}
    structure as its Boopsi message.

@{"OM_DISPOSE" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-2-2}
    This method tells an object to dispose of itself.  It uses an Msg as
    its Boopsi message.

@{"OM_SET" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-2-8}
    This method tells an object to set one or more of its attribute
    values.  It uses an @{"opSet" link 12-2 37} structure as its Boopsi message.

@{"OM_UPDATE" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-2-9}
    This method tells an object to update one or more of its attribute
    values.  It uses an @{"opUpdate" link 12-2-2-2 14} structure as its Boopsi message.

@{"OM_GET" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-2-7}
    This method tells an object to report an attribute value.  It uses an
    @{"opGet" link 12-2-2-3} structure as its Boopsi message.

@{"OM_ADDTAIL" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-2-3}
    This method tells an object to add itself to the end of an Exec list.
    It uses an @{"opAddTail" link ADCD_v1.2:Inc&AD2.1/includes/intuition/classusr.h/MAIN 115} structure as its Boopsi message.

@{"OM_REMOVE" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-2-4}
    This method tells an object to remove itself from an Exec list.  It
    uses an Msg as its Boopsi message.

@{"OM_ADDMEMBER" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-2-5}
    This method tells an object to add an object to its broadcast list.
    It uses an @{"opMember" link 12-1-5 42} structure as its Boopsi message.

@{"OM_REMMEMBER" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-2-6}
    This method tells an object to remove an object from its broadcast
    list.  It uses an @{"opMember" link 12-1-5 42} structure as its Boopsi message.

@{"OM_NOTIFY" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-2-10}
    This method tells an object to broadcast an attribute change to its
    broadcast list.  It uses an @{"opSet" link 12-2 37} structure as its Boopsi message.

Of these, @{"rkmmodelclass" link 12-2-1} has to process OM_NEW, OM_SET, OM_UPDATE, and
OM_GET.

@{" OM_NEW " link 12-2-2-1}            @{" OM_GET " link 12-2-2-3}                @{" RKMModel.c " link 12-2-2-5}
@{" OM_SET/OM_UPDATE " link 12-2-2-2}  @{" Making the New Class " link 12-2-2-4}

@ENDNODE

@NODE 12-2-2-1 "12 / / Writing The Dispatcher / OM_NEW"
The @{"OM_NEW" link 12-2-2 20} method returns a pointer to a newly created Boopsi object, or
NULL if it failed to create the object.  This method receives the
following message structure (defined in <intuition/@{"classusr.h" link ADCD_v1.2:Inc&AD2.1/includes/intuition/classusr.h/MAIN 76}>):

    /* The OM_NEW method uses the same structure as OM_SET */

    struct opSet {
        ULONG             MethodID;
        struct TagItem    *ops_AttrList;
        struct GadgetInfo *ops_GInfo;
    };

The ops_AttrList field contains a pointer to a @{"TagItem" link ADCD_v1.2:Reference_Library/Libraries/Lib_37/37-1-1} array of
attribute/value pairs.  These contain the initial values of the new
object's attributes.  The ops_GInfo field is always NULL for the @{"OM_NEW" link 12-2-2 20}
method.

Unlike other methods, when a dispatcher gets an @{"OM_NEW" link 12-2-2 20} message, the object
pointer (recvobject from the @{"dispatchRKMModel()" link 12-2-2} prototype above) does not
point to an object.  It doesn't make sense for recvobject to point to an
object because the idea is to create a new object, not act on an existing
one.

The pointer normally used to pass a Boopsi object is instead used to pass
the address of the object's "true class".  An object's true class is the
class of which the object is an instance.

The first thing the dispatcher does when it processes an @{"OM_NEW" link 12-2-2 20} message is
pass the OM_NEW message on to its superclass's dispatcher. It does this
using the amiga.lib function @{"DoSuperMethodA()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/DoSuperMethodA()}:

    ULONG DoSuperMethodA(Class *cl, Object *trueclass, Msg msg);

Each dispatcher passes control to its superclass.  Eventually the message
will arrive at the @{"rootclass" link 12-1 50} dispatcher.  The @{"OM_NEW" link 12-2-2 20} method in the
rootclass dispatcher looks at the object's true class (trueclass from the
prototype) to find out which class dispatcher is trying to create a new
object.  Note that trueclass is not necessarily the same as the current
dispatcher's class (cl from the @{"dispatchRKMModel()" link 12-2-2} prototype above),
although this would be the case if the object's true class is a subclass
of the current dispatcher's class.

The @{"rootclass" link 12-1 50} dispatcher uses the true class to find out how much memory
to allocate for the object's instance data.  Each class keeps a record of
how much memory its local instance data requires.  The rootclass
dispatcher also looks at each class between the true class and rootclass
to find out much memory the local instance data for those classes require.
The rootclass dispatcher totals the amount of local instance data memory
needed by the true class and each of its superclasses and allocates that
much memory.

If all goes well, the @{"rootclass" link 12-1 50} dispatcher increments a private field in
the true class that keeps track of how many instances of the true class
there currently are.  It then returns a pointer to the newly created
object and passes control back to the subclass dispatcher that called it,
which is @{"icclass" link 12-1 55} in the case of @{"rkmmodelclass" link 12-2-1}.  If there was a problem,
the rootclass dispatcher does not increment the object count and passes
back a NULL.

When the @{"rootclass" link 12-1 50} dispatcher returns, the @{"icclass" link 12-1 55} dispatcher regains
control from @{"DoSuperMethodA()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/DoSuperMethodA()}.  DoSuperMethodA() will return either a
pointer to the new object or else it returns NULL if there was an error.
Although the rootclass dispatcher allocated all the memory the object
needs, it only initialized the instance data local to rootclass. Now it's
the icclass dispatcher's turn to do some work.  It has to initialize the
instance data that is local to icclass.

A dispatcher finds its local instance data by using the INST_DATA() macro
(defined in <intuition/@{"classes.h" link ADCD_v1.2:Inc&AD2.1/includes/intuition/classes.h/MAIN 46}>):

   void *INST_DATA(Class *localclass, Object *object);

INST_DATA() takes two arguments, a pointer to a class and a pointer to the
object.  The INST_DATA() macro returns a pointer to the instance data
local to localclass.  When the @{"icclass" link 12-1 55} dispatcher was called, it received
three arguments, one of which was a pointer to the local class (icclass).
The icclass dispatcher passes this pointer and the new object pointer it
got from @{"DoSuperMethodA()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/DoSuperMethodA()} to INST_DATA() to get a pointer to the instance
data local to icclass.

After initializing its local instance data, the @{"icclass" link 12-1 55} dispatcher passes
control back to the @{"modelclass" link 12-1-5 13} dispatcher, which in turn, initializes the
instance data local to modelclass.  Finally, the @{"rkmmodelclass" link 12-2-1} dispatcher
regains control and now has to take care of its local instance data.

To find its local instance data, the @{"rkmmodelclass" link 12-2-1} dispatcher needs a
pointer to its Class and a pointer to the new object.  The dispatcher
function gets its Class pointer as its first argument (cl from the
@{"dispatchRKMModel()" link 12-2-2} prototype above).  It gets the new object pointer as
the return value from @{"DoSuperMethodA()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/DoSuperMethodA()}.  In this case, INST_DATA() returns
a pointer to an @{"RKMModData" link 12-2-1-1 18} structure.

Now the dispatcher has to initialize its local instance data.  It has to
scan through the tag list passed in the @{"OM_NEW" link 12-2-2 20} message looking for initial
values for the @{"RKMMOD_CurrVal" link 12-2-1} and @{"RKMMOD_Limit" link 12-2-1-1} attributes. As an
alternative, the dispatcher's OM_NEW method can use its @{"OM_SET" link 12-2-2 28} method to
handle initializing these "settable" attributes.

Finally, the dispatcher can return.  When the dispatcher returns from an
@{"OM_NEW" link 12-2-2 20} method, it returns a pointer to the new object.

If the @{"OM_NEW" link 12-2-2 20} method fails, it should tell the partially initialized
object it got from its superclass's dispatcher to dispose of itself (using
@{"OM_DISPOSE" link 12-2-2 24}) and return NULL.

@ENDNODE

@NODE 12-2-2-2 "12 / / Writing The Dispatcher / OM_SET/OM_UPDATE"
For the @{"OM_SET" link 12-2-2 28} message, the @{"rkmmodelclass" link 12-2-1} dispatcher steps through the
attribute/value pairs passed to it in the OM_SET message looking for the
local attributes (see @{"OM_NEW" link 12-2-2-1} for the OM_SET message structure).  The
@{"RKMMOD_Limit" link 12-2-1-1} attribute is easy to process.  Just find it and record the
value in the local @{"RKMModData" link 12-2-1-1 18}.vallimit field.

Because the function of the @{"rkmmodelclass" link 12-2-1}'s @{"OM_SET" link 12-2-2 28} and @{"OM_UPDATE" link 12-2-2 32} methods
are almost identical, the rkmmodelclass dispatcher handles them as the
same case.  The only difference is that, because the OM_UPDATE message
comes from another Boopsi object, the OM_UPDATE method can report on
transitory state changes of an attribute.  For example, when the user
slides a Boopsi prop gadget, that prop gadget sends out an interim
OM_UPDATE message for every interim value of @{"PGA_Top" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-11-8}.  When the user lets
go of the prop gadget, the gadget sends out a final OM_UPDATE message.
The OM_UPDATE message is almost identical to the OM_SET message:

    #define OPUF_INTERIM    (1<<0)

    /* the OM_NOTIFY method uses the same structure */

    struct opUpdate {
        ULONG             MethodID;
        struct TagItem    *opu_AttrList;
        struct GadgetInfo *opu_GInfo;
        ULONG             opu_Flags;      /* The extra field */
    };

A dispatcher can tell the difference between an interim and final
@{"OM_UPDATE" link 12-2-2 32} message because the OM_UPDATE message has an extra field on it
for flags.  If the low order bit (the OPUF_INTERIM bit) is set, this is an
interim OM_UPDATE message.  The interim flag is useful to a class that
wants to ignore any transitory messages, processing only final attribute
values.  Because @{"rkmmodelclass" link 12-2-1} wants to process all changes to its
attributes, it processes all OM_UPDATE messages.

The @{"RKMMOD_CurrVal" link 12-2-1} attribute is a little more complicated to process. The
dispatcher has to make sure the new current value is within the limits set
by @{"RKMMOD_Limit" link 12-2-1-1}, then record that new value in the local
@{"RKMModData" link 12-2-1-1 18}.currval field.  Because other objects need to hear about
changes to RKMMOD_CurrVal,  the dispatcher has to send a notification
request.  It does this by sending itself an @{"OM_NOTIFY" link 12-2-2 56} message.  The
OM_NOTIFY message tells an object to notify its targets (its @{"ICA_TARGET" link 12-1-3 20}
and the objects in its broadcast list) about an attribute change.  The
OM_NOTIFY method does this by sending @{"OM_UPDATE" link 12-2-2 32} messages to all of an
object's targets.

The @{"rkmmodelclass" link 12-2-1} dispatcher does not handle the @{"OM_NOTIFY" link 12-2-2 56} message itself.
It inherits this method from @{"modelclass" link 12-1-5 13}, so the rkmmodelclass dispatcher
passes OM_NOTIFY messages on to its superclass. To notify its targets, the
rkmmodelclass dispatcher has to construct an OM_NOTIFY message.  The
OM_NOTIFY method uses the same message structure as @{"OM_UPDATE. " link 12-2-2 32} Using the
stack-based version of @{"DoSuperMethodA()" link 12-2-2-1 27}, @{"DoSuperMethod()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/DoSuperMethod()}, the dispatcher
can build an OM_NOTIFY message on the stack:

     . . .

    struct TagItem tt[2];
    struct opUpdate *msg;
     . . .

    tt[0].ti_Tag  = RKMMOD_CurrVal;  /* make a tag list.  */
    tt[0].ti_Data = mmd->currval;
    tt[1].ti_Tag  = TAG_END;

    DoSuperMethod(cl, o, OM_NOTIFY, tt, msg->opu__GInfo,
                  ((msg->MethodID == OM_UPDATE) ? (msg->opu_Flags) : 0L));
     . . .

Because the @{"OM_NOTIFY" link 12-2-2 56} needs a tag list of attributes about which to issue
updates, the dispatcher builds a tag list containing just the
@{"RKMMOD_CurrVal" link 12-2-1} tag and its new value.  The dispatcher doesn't use the tag
list passed to it in the @{"OM_UPDATE" link 12-2-2 32}/OM_NOTIFY message because that list can
contain many other attributes besides RKMMOD_CurrVal.

The msg variable in the @{"DoSuperMethod()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/DoSuperMethod()} call above is the @{"OM_SET" link 12-28} or
@{"OM_UPDATE" link 12-2-2 32} message that was passed to the dispatcher.  The dispatcher uses
that structure to find a pointer to the @{"GadgetInfo" link 12-3-1 23} structure that the
@{"OM_NOTIFY" link 12-2-2 56} message requires.  The GadgetInfo structure comes from Intuition
and contains information that Boopsi gadgets need to render themselves.
For the moment, don't worry about what the GadgetInfo structure actually
does, just pass it on.  The targets of an rkmmodel will probably need it.

Notice that the dispatcher has to test to see if the message is an @{"OM_SET" link 12-2-2 28}
or @{"OM_UPDATE" link 12-2-2 32} so it can account for the opu_Flags field at the end of the
OM_UPDATE message.

Processing the @{"RKMMOD_Up" link 12-2-1-1 8} and @{"RKMMOD_Down" link 12-2-1-1 8} attributes is similar to the
@{"RKMMOD_CurrVal" link 12-2-1} attribute.  When the dispatcher sees one of these, it has
to increment or decrement the local @{"RKMModData" link 12-2-1-1 18}.currval, making sure
RKMModData.currval is within limits.  The dispatcher then sends an
@{"OM_NOTIFY" link 12-56} message to the superclass about the change to RKMModData.currval.

The return value from the dispatcher's @{"OM_SET" link 12-2-2 28} method depends on the what
effect the attribute change has to the visual state of the objects in the
rkmmodel's broadcast list.  If an attribute change will not affect the
visual state of the rkmmodel's objects, the OM_SET method returns zero.
If the attribute change could trigger a change to the rkmmodel's objects,
it returns something besides zero. For example, the @{"rkmmodelclass" link 12-2-1} OM_SET
method returns 1L if an rkmmodel's @{"RKMMOD_CurrVal" link 12-2-1}, @{"RKMMOD_Up" link 12-2-1-1 8}, or
@{"RKMMOD_Down" link 12-2-1-1 8} attribute is changed.

At some point the @{"rkmmodelclass" link 12-2-1} dispatcher has to allow its superclasses
to process these attributes it inherits.  Normally a dispatcher lets the
superclass process its attributes before attempting to process any local
attributes.  The rkmmodelclass dispatcher does this by passing on the
@{"OM_SET" link 12-2-2 28} or @{"OM_UPDATE" link 12-2-2 32} message using @{"DoSuperMethodA()" link 12-2-2-1 27} (inheritance at work!).
As an alternative, the dispatcher can use the amiga.lib function
@{"SetSuperAttrs()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/SetSuperAttrs()}.  See the @{"amiga.lib" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/MAIN} Autodocs for more details on this
function.

@ENDNODE

@NODE 12-2-2-3 "12 / / Writing The Dispatcher / OM_GET"
The rkmmodel only has one "gettable" attribute: @{"RKMMOD_CurrVal" link 12-2-1}, which
makes processing it easy.  The @{"OM_GET" link 12-2-2 36} message looks like this (defined in
<intuition/@{"classusr.h" link ADCD_v1.2:Inc&AD2.1/includes/intuition/classusr.h/MAIN 106}>):

    struct opGet {
        ULONG MethodID;     /* OM_GET */
        ULONG opg_AttrID;   /* The attribute to retrieve */
        ULONG *opg_Storage; /* a place to put the attribute's value */
    };

When the @{"rkmmodelclass" link 12-2-1} dispatcher receives an @{"OM_GET" link 12-2-2 36} message with an
opg_AttrID equal to @{"RKMMOD_CurrVal" link 12-2-1}, it copies the current value
(@{"RKMModData" link 12-2-1-1 18}).currval to the memory location opg_Storage points to and
returns a value of TRUE.  The TRUE indicates that there was no error.  If
opg_AttrID is not RKMMOD_CurrVal, the dispatcher should let its superclass
handle this message.

The @{"rkmmodelclass" link 12-2-1} dispatcher can take advantage of the fact that the only
"gettable" attribute available to an rkmmodel is @{"RKMMOD_CurrVal" link 12-2-1} (the
attributes defined by @{"modelclass" link 12-1-5 13} and @{"icclass" link 12-1 55} are not gettable--see the
Boopsi Class Reference in the @{"Appendix B" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/MAIN} of this manual for more details
on which attributes are "settable", "gettable", etc.).  If opg_AttrID is
not RKMMOD_CurrVal, the rkmmodelclass dispatcher can return FALSE,
indicating that the attribute was not "gettable".

If the @{"rkmmodelclass" link 12-2-1} dispatcher comes across any other messages besides
@{"OM_NEW" link 12-2-2 20}, @{"OM_SET" link 12-2-2 28}, @{"OM_UPDATE" link 12-2-2 32}, and @{"OM_GET" link 12-2-2 36} message, it blindly passes them on
to its superclass for processing.

@ENDNODE

@NODE 12-2-2-4 "12 / / Writing The Dispatcher / Making the New Class"
The Intuition function @{"MakeClass()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/MakeClass()} creates a new Boopsi class:

    Class *MakeClass(UBYTE *newclassID, UBYTE *pubsuperclassID,
                     Class *privsuperclass, UWORD instancesize,
                     ULONG flags);

If the new class is going to be public, newclassID is a string naming the
new class.  If the new class is private, this field is NULL.  The next two
fields tell @{"MakeClass()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/MakeClass()} where to find the new class's superclass.  If the
superclass is public, pubsuperclassID points to a string naming that
public superclass and the privsuperclass pointer is NULL.  If the
superclass is private, privsuperclass points to that superclass's Class
structure and pubsuperclassID is NULL. The size of the new class's local
instance data is instancesize.  The last parameter, flags, is for future
enhancement.  For now, make this zero.

If it is successful, @{"MakeClass()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/MakeClass()} returns a pointer to the new class,
otherwise it returns NULL.  When MakeClass() is successful, it also takes
measures to make sure no one can "close" the new class's superclass (using
@{"FreeClass()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/FreeClass()}).  It does this by incrementing a private field of the
superclass that keeps track of how many subclasses the superclass
currently has.

After successfully creating a class, an application has to tell the class
where its dispatcher is. The Class pointer (defined in
<intuition/@{"classes.h" link ADCD_v1.2:Inc&AD2.1/includes/intuition/classes.h/MAIN}>) returned by @{"MakeClass()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/MakeClass()} contains a Hook structure
called cl_Dispatcher, which is used to call the dispatcher.  The
application has to initialize this hook:

    myclass->cl_Dispatcher.h_Entry = HookEntry;
    /* HookEntry() is defined in amiga.lib */

    myclass->cl_Dispatcher.h_SubEntry = dispatchRKMModel;

The h_Entry field points to a function in amiga.lib that copies the
function arguments to where the dispatcher expects them. See the
"@{"Callback Hooks" link ADCD_v1.2:Reference_Library/Libraries/Lib_37/37-2-1}" section of the "Utility Library" chapter of this manual for
more details.

To make a class public instead of private, an application has to call
AddClass() in addition to giving the class a name in @{"MakeClass()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/MakeClass()}.
AddClass() takes one argument, a pointer to a valid Class structure that
has been initialized as a public class by MakeClass().  To remove a public
class added to the system with AddClass(), pass the public class pointer
to RemoveClass().  See the Intuition Autodocs for more details on
@{"AddClass()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/AddClass()} and @{"RemoveClass()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/RemoveClass()}.

@ENDNODE

@NODE 12-2-2-5 "12 / / Writing The Dispatcher / RKMModel.c"
The following code, RKMModel.c,  makes up an initialization function and
the dispatcher function for a private class informally called
@{"rkmmodelclass" link 12-2-1}.

    @{" RKMModel.c " link ADCD_v1.2:Reference_Library/Libraries/lib_examples/RKMModel.c/MAIN}

Below is a diagram showing how an application could use an @{"rkmmodelclass" link 12-2-1}
object:

    @{" Figure 12-5: Rkmmodelclass Object Diagram " link "ADCD_v1.2:Reference_Library/lib_pics/12-5.iff/Main"}

In this diagram, the application uses @{"buttongclass" link 12-1-2-2 14} Boopsi gadgets to send
the @{"rkmmodelclass" link 12-2-1} the @{"RKMMOD_Up" link 12-2-1-1 8} and @{"RKMMOD_Down" link 12-2-1-1 8} attribute pulses.

The example takes advantage of an odd feature of @{"buttongclass" link 12-1-2-2 14}.  When the
user clicks on a buttongclass gadget, it sends an @{"OM_UPDATE" link 12-2-2 32} to its
@{"ICA_TARGET" link 12-1-3 20}, even though no Boopsi attribute of buttongclass has changed.
It does this because it's a convenient way to report button clicks.

Whenever a gadget sends a notification, the list of attribute/value pairs
in the @{"OM_NOTIFY" link 12-2-2 56} message always contains the gadget's @{"GA_ID" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-10-15}. This is an
easy way for the button to inform its target of its ID so the target knows
which gadget sent the @{"OM_UPDATE" link 12-2-2 32} message.  When a @{"buttongclass" link 12-1-2-2 14} sends a
notification because of a button click, it only sends out an OM_UPDATE
about its GA_ID because none of its attributes changed.

When the user clicks one of the buttons in the @{"rkmmodelclass" link 12-2-1} diagram, the
button uses an @{"ICA_MAP" link 12-1-3 63} to map its @{"GA_ID" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-10-15} to one of the "dummy" pulse
attributes, @{"RKMMOD_Up" link 12-2-1-1 8} and @{"RKMMOD_Down" link 12-2-1-1 8}.  When the rkmmodel receives the
@{"OM_UPDATE" link 12-2-2 32} message about RKMMOD_Up or RKMMOD_Down, it increments or
decrements its internal value.

There is one more important thing to note about @{"rkmmodelclass" link 12-2-1}. Looking at
the rkmmodelclass Object diagram above, an rkmmodel's @{"RKMMOD_CurrVal" link 12-2-1}
changes because it received an @{"OM_UPDATE" link 12-2-2 32} message from one of its gadgets.
RKMMOD_CurrVal can also change if the application explicitly set
RKMMOD_CurrVal using @{"SetAttrs()" link 12-1-1-4} or @{"SetGadgetAttrs()" link 12-1-1-4 5}.

The primary difference between the @{"OM_SET" link 12-2-2 28} message that @{"SetAttrs()" link 12-1-1-4} sends
and the OM_SET message that @{"SetGadgetAttrs()" link 12-1-1-4 5} sends is that SetAttrs()
passes a NULL in @{"opSet.ops_GInfo" link 12-2 37} instead of a @{"GadgetInfo" link 12-3-1 23} pointer.  This
doesn't present a problem for the rkmmodel object, because it doesn't use
the GadgetInfo structure.  The problem is that when the rkmmodel notifies
its targets, some of which are gadgets, they can't update their visual
state because they need a GadgetInfo to render themselves.  For this
reason, the @{"rkmmodelclass" link 12-2-1} dispatcher returns a positive non-zero value
when an attribute change occurs that could cause a change in the visual
state of any objects in its broadcast list.  An application that uses
rkmmodelclass must test the return value when calling SetAttrs() on an
rkmmodelclass object to tell if the attribute change requires a visual
refresh of the gadgets (see the Intuition Autodocs for @{"RefreshGadgets()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/RefreshGadgets()}).

    Boopsi Dispatchers Can Execute on Intuition's Context.
    ------------------------------------------------------
    Notice that the gadgets in the figure above send @{"OM_UPDATE" link 12-2-2 32} messages
    to the rkmmodel when the user manipulates them.  Because Intuition
    handles the user input that triggers the OM_UPDATE messages,
    Intuition itself is sending the OM_UPDATE messages.  This means the
    @{"rkmmodelclass" link 12-2-1} dispatcher must be able to run on Intuition's context,
    which puts some limitations on what the dispatcher is permitted to
    do: it can't use dos.library, it can't wait on application signals or
    message ports, and it can't call any Intuition functions which might
    wait on Intuition.

Although @{"rkmmodelclass" link 12-2-1} serves as an example of a class, it leaves a little
to be desired in a real-world implementation.  To create the
"prop-integer-up/down" super gadget from the diagram above, the
application has to create, initialize, and link nine Boopsi objects, which
is tedious, especially if the application needs several of these super
gadgets.  Ideally, all these functions would be rolled into some subclass
of @{"gadgetclass" link 12-1-2-2}.  If there were such a class, an application would only
have to create one instance of this subclass to get such a gadget.  When
the subclass received an @{"OM_NEW" link 12-2-2 20} message, it would take care of creating,
initializing, and linking all of the Boopsi objects that make up the whole
super gadget.

@ENDNODE

@NODE 12-2-3 "12 / Boopsi Class / White Boxes - The Transparent Base Classes"
Boopsi gadgets and images were designed to be backwards compatible with
the old Intuition @{"Gadget" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9}s and @{"Image" link ADCD_v1.2:Reference_Library/Libraries/Lib_8/8-2-1}s, so as part of their instance data,
both types of objects have the old Intuition structures built into them.
When @{"NewObject()" link 12-1-1-2 25} creates a new gadget or image object, the pointer it
returns points to the object's embedded Gadget or Image corresponding
structure. Because Intuition can tell the difference between Boopsi images
and gadgets and the original images and gadgets, applications can use
Boopsi images and gadgets interchangeably with the older Intuition
entities.

Although normally considered a "programming sin", in some cases it is
legal for class dispatchers to directly manipulate some internal fields of
certain Boopsi objects.  For compatibility reasons, a Boopsi image or
gadget object contains an actual @{"Image" link ADCD_v1.2:Reference_Library/Libraries/Lib_8/8-2-1} or @{"Gadget" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9} structure.  These objects
are instances of the Transparent Base Classes, @{"imageclass" link 12-1-2-1} and @{"gadgetclass" link 12-1-2-2}.

To change an attribute of a Boopsi object, you normally invoke the set
method, @{"OM_SET. " link 12-2-2 28} The Intuition functions @{"SetAttrs()" link 12-1-1-4} and @{"SetGadgetAttrs()" link 12-1-1-4 5}
invoke this method.  A Boopsi class is informed of any attribute change at
that time, allowing it to react to this change.  The reaction can include
validating the changed attribute, changing other attributes to match, or
informing other objects of the change.  That is the inherent advantage of
using function calls to change attributes.

When using conventional images and gadgets, you generally modify the
structure's fields directly.  This operation is very fast.  For
conventional images and gadgets, there is no class that needs to know
about the changes, so there is no problem.  However, this is untrue of
Boopsi images and gadgets.  Although directly modifying the Boopsi
object's internal structure would provide a performance increase over
using the Boopsi @{"OM_SET" link 12-2-2 28} mechanism, altering a Boopsi object's internal
structure directly will not give the class the opportunity to react to any
structure changes.  This violates the Boopsi concept, and therefore cannot
be done in general.

In order to provide a balance between the flexibility of function-access
and the performance of direct-access, the transparent base classes
@{"imageclass" link 12-1-2-1} and @{"gadgetclass" link 12-1-2-2} do not depend on being informed of changes to
certain fields in the internal @{"Image" link ADCD_v1.2:Reference_Library/Libraries/Lib_8/8-2-1} and @{"Gadget" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9} structures.  This means
that it is OK for the dispatchers of direct subclasses of imageclass and
gadgetclass to modify specific fields of Boopsi images or gadgets.
Applications and indirect subclass dispatchers of imageclass or
gadgetclass may not modify those fields, since their parent classes may
depend on hearing about changes to these fields, which the @{"SetAttrs()" link 12-1-1-4} call
(or a similar function) provides.

For dispatchers of direct subclasses of @{"imageclass" link 12-1-2-1}, the following are the
only fields of the @{"Image" link ADCD_v1.2:Reference_Library/Libraries/Lib_8/8-2-1} structure that are alterable:

    @{"LeftEdge" link ADCD_v1.2:Reference_Library/Libraries/Lib_8/8-2-1 17}      @{"Width" link ADCD_v1.2:Reference_Library/Libraries/Lib_8/8-2-1 32}     @{"ImageData" link ADCD_v1.2:Reference_Library/Libraries/Lib_8/8-2-1 47}
    @{"TopEdge" link ADCD_v1.2:Reference_Library/Libraries/Lib_8/8-2-1 17}       @{"Height" link ADCD_v1.2:Reference_Library/Libraries/Lib_8/8-2-1 32}    @{"PlanePick" link ADCD_v1.2:Reference_Library/Libraries/Lib_8/8-2-1 63}
    @{"PlaneOnOff" link ADCD_v1.2:Reference_Library/Libraries/Lib_8/8-2-1 69}

For dispatchers of direct subclasses of @{"gadgetclass" link 12-1-2-2}, the following are the
only fields of the @{"Gadget" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9} structure that are alterable:

    @{"LeftEdge" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9 33}    @{"Flags" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9 48}           @{"GadgetText" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9 111}
    @{"TopEdge" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9 33}     @{"GadgetType" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9 58}      @{"SpecialInfo" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9 125}
    @{"Width" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9 33}       @{"GadgetRender" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9 91}    @{"Activation" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9 53}
    @{"Height" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9 33}      @{"SelectRender" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9 102}

Under no circumstances may an application or an indirect subclass modify
one of these fields, even if the subclass knows the superclasses do not
depend on notification for this field.  This is the only way to preserve
the possibility for future enhancements to that superclass.  Note that
these fields are not alterable while the gadget or image object is in use
(for example, when it is attached to a window).

@ENDNODE

@NODE 12-3 "12 Boopsi--Object Oriented Intuition / Boopsi Gadgets"
One of the major enhancements to Intuition for Release 2 is the
implementation of customizable Boopsi gadgets.  Boopsi gadgets are not
limited by dependencies upon Intuition @{"Image" link ADCD_v1.2:Reference_Library/Libraries/Lib_8/8-2-1} and @{"Gadget" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9} structures.
Unlike Release 1.3 gadgets, which were handled exclusively by Intuition,
Boopsi gadgets handle their own rendering and their own user input.

Since Boopsi gadgets draw themselves, there is almost no restriction on
what they can look like.  A Boopsi gadget can use graphics.library
@{"RastPort" link ADCD_v1.2:Reference_Library/Libraries/Lib_27/27-4-1} drawing functions to draw vector-based imagery which the gadget
can scale to any dimension.  Instead of just a two-state Boolean gadget, a
Boopsi gadget can have any number of states, each of which has its own
imagery.  If a programmer wanted to he could even make a Boopsi gadget
that uses the animation system to render itself.

Because Boopsi gadgets handle their own input, they see all the user's
input, which the gadget is free to interpret.  While the user has a Boopsi
gadget selected, the gadget can track mouse moves, process mouse and
keyboard key presses, or watch the timer events.

The power of a Boopsi gadget is not limited to its ability to handle its
own rendering and user input.  Boopsi gadgets are also Boopsi objects so
the gain all the benefits Boopsi provides.  This means all Boopsi gadgets
inherit the methods and attributes from their superclasses.  Boopsi
gadgets can use Boopsi images to take care of rendering their imagery.  A
Boopsi gadget could be a "composite" gadget that is composed of several
Boopsi gadgets, images, and models.

@{" The Boopsi Gadget Methods " link 12-3-1}  @{" The Active Gadget " link 12-3-2}

@ENDNODE

@NODE 12-3-1 "12 / Boopsi Gadgets / The Boopsi Gadget Methods"
Intuition drives a Boopsi gadget by sending it Boopsi messages. Intuition
uses a series of five Boopsi methods:

@{"GM_RENDER" link 12-3-1-1}       This method tells the gadget to render itself.

@{"GM_HITTEST" link 12-3-1-2}      This method asks a gadget whether it has been "hit" by a
                mouse click.

@{"GM_GOACTIVE" link 12-3-1-3}     This method asks a gadget if it wants to be the active
                gadget.

@{"GM_HANDLEINPUT" link 12-3-1-3}  This method passes a gadget an input event.

@{"GM_GOINACTIVE" link 12-3-1-4}   This method tells a gadget that it is no longer active.

The formats of each of these Boopsi messages differ, but they all have two
things in common.  Like all Boopsi messages, each starts with their
respective method ID.  For each of these methods, the method ID field is
followed by a pointer to a GadgetInfo structure (defined in
<intuition/@{"cghooks.h" link ADCD_v1.2:Inc&AD2.1/includes/intuition/cghooks.h/MAIN 22}>).  The GadgetInfo structure contains information
about the display on which the gadget needs to render itself:


struct GadgetInfo {
    struct Screen          *gi_Screen;
    struct Window          *gi_Window;     /* null for screen gadgets */
    struct Requester       *gi_Requester;  /* null if not GTYP_REQGADGET */

    /* rendering information: don't use these without cloning/locking.
     * Official way is to call ObtainGIRPort()
     */
    struct RastPort        *gi_RastPort;
    struct Layer           *gi_Layer;

    /* copy of dimensions of screen/window/g00/req(/group)
     * that gadget resides in.  Left/Top of this box is
     * offset from window mouse coordinates to gadget coordinates
     *  screen gadgets:                 0,0 (from screen coords)
     *  window gadgets (no g00):        0,0
     *  GTYP_GZZGADGETs (borderlayer):  0,0
     *  GZZ innerlayer gadget:          borderleft, bordertop
     *  Requester gadgets:              reqleft, reqtop
     */
    struct IBox            gi_Domain;

    /* these are the pens for the window or screen */
    struct {
        UBYTE   DetailPen;
        UBYTE   BlockPen;
    }                      gi_Pens;

    /* the Detail and Block pens in gi_DrInfo->dri_Pens[] are
     * for the screen.  Use the above for window-sensitive colors.
     */
    struct DrawInfo        *gi_DrInfo;

    /* reserved space: this structure is extensible
     * anyway, but using these saves some recompilation
     */
    ULONG                  gi_Reserved[6];
};


All the fields in this structure are read only.

Although this structure contains a pointer to the gadget's @{"RastPort" link ADCD_v1.2:Reference_Library/Libraries/Lib_27/27-4-1}
structure, applications should not use it for rendering.  Instead, use the
intuition.library function @{"ObtainGIRPort()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/ObtainGIRPort()} to obtain a copy of the
GadgetInfo's RastPort.  When the gadget is finished with this RastPort, it
should call @{"ReleaseGIRPort()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/ReleaseGIRPort()} to relinquish the RastPort.

@{" GM_RENDER " link 12-3-1-1}   @{" GM_GOACTIVE/GM_HANDLEINPUT " link 12-3-1-3}
@{" GM_HITTEST " link 12-3-1-2}  @{" GM_GOINACTIVE " link 12-3-1-4}

@ENDNODE

@NODE 12-3-1-1 "12 / / The Boopsi Gadget Methods / GM_RENDER"
Every time Intuition feels it is necessary to redraw a Boopsi gadget, it
sends a gadget a GM_RENDER message.  The GM_RENDER message (defined in
<intuition/@{"gadgetclass.h" link ADCD_v1.2:Inc&AD2.1/includes/intuition/gadgetclass.h/MAIN 186}>) tells a gadget to render itself:

    struct gpRender
    {
        ULONG             MethodID;   /* GM_RENDER */
        struct GadgetInfo *gpr_GInfo;
        struct RastPort   *gpr_RPort; /* all ready for use */
        LONG              gpr_Redraw; /* might be a "highlight pass" */
    };

Some events that cause Intuition to send a GM_RENDER are: an application
passed the gadget to @{"OpenWindow()" link ADCD_v1.2:Reference_Library/Libraries/Lib_4/4-2-1}, the user moved or resized a gadget's
window, or an application explicitly asked Intuition to refresh some
gadgets.

The GM_RENDER message contains a pointer to the gadget's @{"RastPort" link ADCD_v1.2:Reference_Library/Libraries/Lib_27/27-4-1} so the
GM_RENDER method does not have to extract it from the gpr_GInfo @{"GadgetInfo" link 12-3-1 23}
structure using @{"ObtainGIRPort()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/ObtainGIRPort()}).  The gadget renders itself according to
how much imagery it needs to replace.  The gpr_Redraw field contains one
of three values:

GREDRAW_REDRAW  Redraw the entire gadget.

GREDRAW_UPDATE  The user has manipulated the gadget, causing a change
                to its imagery. Update only that part of the gadget's
                imagery that is effected by the user manipulating the
                gadget (for example, the knob and scrolling field of
                the prop gadget).

GREDRAW_TOGGLE  If this gadget supports it, toggle to or from the
                highlighting imagery.

Intuition is not the only entity that calls this method.  The gadget's
other methods may call this method to render the gadget when it goes
through state changes.  For example, as a prop gadget is following the
mouse from the gadget's @{"GM_HANDLEINPUT" link 12-3-1-3 26} method, the gadget could send
itself GM_RENDER messages, telling itself to update its imagery according
to where the mouse has moved.

@ENDNODE

@NODE 12-3-1-2 "12 / / The Boopsi Gadget Methods / GM_HITTEST"
When Intuition gets a left mouse button click in a window, one of the
things it does is check through the window's list of gadgets to see if
that click was inside the bounds of a gadget's @{"Gadget" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9} structure (using the
@{"LeftEdge" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9 33}, @{"TopEdge" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9 33}, @{"Width" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9 33}, and @{"Height" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9 33} fields).  If it was (and that gadget
is a Boopsi gadget), Intuition sends that gadget a GM_HITTEST message
(defined in <intuition/@{"gadgetclass.h" link ADCD_v1.2:Inc&AD2.1/includes/intuition/gadgetclass.h/MAIN 174}>):

    struct gpHitTest
    {
        ULONG             MethodID;     /* GM_HITTEST   */
        struct GadgetInfo *gpht_GInfo;
        struct
        {
            WORD X;     /* Is this point inside of the gadget? */
            WORD Y;
        } gpht_Mouse;
    };

This message contains the coordinates of the mouse click.  These
coordinates are relative to the upper-left of the gadget (@{"LeftEdge" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9 33},
@{"TopEdge" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9 33}).

Because Intuition can only tell if the user clicked inside gadget's
"bounding box", Intuition only knows that the click was close to the
gadget.  Intuition uses the GM_HITTEST to ask the gadget if the click was
really inside the gadget.  The gadget returns GMR_GADGETHIT (defined in
<intuition/@{"gadgetclass" link ADCD_v1.2:Inc&AD2.1/includes/intuition/gadgetclass.h/MAIN 183}>) to tell Intuition that the user hit it,
otherwise it returns zero.  This method allows a gadget to be any shape or
pattern, rather than just rectangular.

@ENDNODE

@NODE 12-3-1-3 "12 / / The Boopsi Gadget Methods / GM_GOACTIVE/GM_HANDLEINPUT"
If a gadget returns @{"GMR_GADGETHIT" link 12-3-1-2 22}, Intuition will send it a GM_GOACTIVE
message (defined in <intuition/@{"gadgetclass.h" link ADCD_v1.2:Inc&AD2.1/includes/intuition/gadgetclass.h/MAIN 168}>):

    struct gpInput /* Used by GM_GOACTIVE and GM_HANDLEINPUT */
    {
        ULONG             MethodID;
        struct GadgetInfo *gpi_GInfo;
        struct InputEvent *gpi_IEvent;
                             /* The input event that triggered this method
                              * (for GM_GOACTIVE, this can be NULL)      */
        LONG              *gpi_Termination;
                             /* For GADGETUP IntuiMessage.Code           */
        struct
        {
            WORD X;          /* Mouse position relative to upper         */
            WORD Y;          /* left corner of gadget (LeftEdge,TopEdge) */
        } gpi_Mouse;
    };

The GM_GOACTIVE message gives a gadget the opportunity to become the
active gadget.  The active gadget is the gadget that is currently
receiving user input.  Under normal conditions, only one gadget can be the
active gadget (it is possible to have more than one active gadget using a
@{"groupgclass" link 12-1-2-2 10} object--See the Boopsi Class Reference in the @{"Appendix B" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-15} of
this manual for more details).

While a gadget is active, Intuition sends it GM_HANDLEINPUT messages. Each
GM_HANDLEINPUT message corresponds to a single @{"InputEvent" link ADCD_v1.2:Inc&AD2.1/includes/devices/inputevent.h/MAIN 198} structure.
These InputEvents can be keyboard presses, timer events, mouse moves, or
mouse button presses.  The message's gpi_IEvent field points to this
InputEvent structure. It's up to the GM_HANDLEINPUT method to interpret
the meaning of these events and update the visual state of the gadget as
the user manipulates the gadget.  For example, the GM_HANDLEINPUT method
of a prop gadget has to track mouse events to see where the user has moved
the prop gadget's knob and update the gadget's imagery to reflect the new
position of the knob.

For the GM_GOACTIVE method, the gpi_IEvent field points to the struct
@{"InputEvent" link ADCD_v1.2:Inc&AD2.1/includes/devices/inputevent.h/MAIN 198} that triggered the GM_GOACTIVE message. Unlike the
GM_HANDLEINPUT message, GM_GOACTIVE's gpi_IEvent can be NULL.  If the
GM_GOACTIVE message was triggered by a function like intuition.library's
@{"ActivateGadget()" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-12-3} and not by a real InputEvent (like the user clicking the
gadget), the gpi_IEvent field will be NULL.

For gadgets that only want to become active as a direct result of a mouse
click, this difference is important.  For example, the prop gadget becomes
active only when the user clicks on its knob.  Because the only way the
user can control the prop gadget is via the mouse, it does not make sense
for anything but the mouse to activate the gadget.  On the other hand, a
string gadget doesn't care how it is activated because, as soon as it's
active, it gets user input from the keyboard rather than the mouse.  Not
all gadgets can become active.  Some gadgets cannot become active because
they have been temporarily disabled (their @{"Gadget.Flags" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9 48} @{"GFLG_DISABLED" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9-1 73} bit
is set).  Other gadgets will not become active because they don't need to
process input.  For example, a toggle gadget won't become active because
it only needs to process one input event, the mouse click that toggles the
gadget (which it gets from the GM_GOACTIVE message). If a toggle gadget
gets a GM_GOACTIVE message and its gpi_IEvent field is not NULL, it will
toggle its state and refuse to "go active".

The GM_GOACTIVE method has to take care of any visual state changes to a
gadget that a GM_GOACTIVE message might trigger.  For example, the toggle
gadget in the previous paragraph has to take care of toggling its visual
state from selected imagery to unselected imagery.  If the gadget goes
through a state change when it becomes the active gadget, (like when a
string gadget positions its cursor) GM_GOACTIVE has to take care of this.

The return values of both GM_GOACTIVE and GM_HANDLEINPUT tell Intuition
whether or not the gadget wants to be active.  A gadget's GM_GOACTIVE
method returns GMR_MEACTIVE (defined in <intuition/@{"gadgetclass.h" link ADCD_v1.2:Inc&AD2.1/includes/intuition/gadgetclass.h/MAIN 211}>) if it
wants to become the active gadget.  A gadget's GM_HANDLEINPUT method
returns GMR_MEACTIVE if it wants to remain the active gadget.  If a gadget
either does not want to become or remain the active gadget, it returns one
of the "go inactive" return values:

GMR_NOREUSE     Tells Intuition to throw away the gpInput.gpi_IEvent
                @{"InputEvent" link ADCD_v1.2:Inc&AD2.1/includes/devices/inputevent.h/MAIN 198}.

GMR_REUSE       Tells Intuition to process the gpInput.gpi_IEvent
                @{"InputEvent" link ADCD_v1.2:Inc&AD2.1/includes/devices/inputevent.h/MAIN 198}.

GMR_NEXTACTIVE  Tells Intuition to throw away the gpInput.gpi_IEvent
                @{"InputEvent" link ADCD_v1.2:Inc&AD2.1/includes/devices/inputevent.h/MAIN 198} and activate the next @{"GFLG_TABCYCLE" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9-1 89} gadget.

GMR_PREVACTIVE  Tells Intuition to throw away the gpInput.gpi_IEvent
                @{"InputEvent" link ADCD_v1.2:Inc&AD2.1/includes/devices/inputevent.h/MAIN 198} and activate the previous @{"GFLG_TABCYCLE" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9-1 89}
                gadget.

GMR_NOREUSE tells Intuition that the gadget does not want to be active and
to throw away the @{"InputEvent" link ADCD_v1.2:Inc&AD2.1/includes/devices/inputevent.h/MAIN 198} that triggered the message.  For example, an
active prop gadget returns GMR_NOREUSE when the user lets go of the left
mouse button (thus letting go of the prop gadget's knob).

For the GM_HANDLEINPUT method, a gadget can also return GMR_REUSE, which
tells Intuition to reuse the @{"InputEvent" link ADCD_v1.2:Inc&AD2.1/includes/devices/inputevent.h/MAIN 198}.  For example, if the user clicks
outside the active string gadget, that string gadget returns GMR_REUSE.
Intuition can now process that mouse click, which can be over another
gadget.  Another case where a string gadget returns GMR_REUSE is when the
user pushes the right mouse button (the menu button).  The string gadget
becomes inactive and the menu button InputEvent gets reused.  Intuition
sees this event and tries to pop up the menu bar.

For the GM_GOACTIVE method, a gadget must not return GMR_REUSE.  If a
gadget gets a GM_GOACTIVE message from Intuition and the message has an
gpi_IEvent, the message was triggered by the user clicking on the gadget.
In this case, Intuition knows that the user is trying to select the
gadget.  Intuition doesn't know if the gadget can be activated, but if it
can be activated, the event that triggered the activation has just taken
place.  If the gadget cannot become active for any reason, it must not let
Intuition reuse that @{"InputEvent" link ADCD_v1.2:Inc&AD2.1/includes/devices/inputevent.h/MAIN 198} as the gadget has already taken care of
the the event's purpose (clicking on the gadget).  In essence, the user
tried to activate the gadget and the gadget refused to become active.

The other two possible return values, GMR_NEXTACTIVE and GMR_PREVACTIVE
were added to the OS for Release 2.04.  These tell Intuition that a gadget
does not want to be active and that the @{"InputEvent" link ADCD_v1.2:Inc&AD2.1/includes/devices/inputevent.h/MAIN 198} should be discarded.
Intuition then looks for the next (GMR_NEXTACTIVE) or previous
(GMR_PREVACTIVE) gadget that has its @{"GFLG_TABCYCLE" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9-1 89} flag set in its
@{"Gadget.Activation" link ADCD_v1.2:Reference_Library/Libraries/Lib_5/5-9 53} field (see the @{"gadgetclass" link 12-1-2-2} @{"GA_TabCycle" link ADCD_v1.2:Reference_Library/Libraries/Lib_B/B-10-18} attribute in the
Boopsi Class Reference in the Appendix B of this manual).

For both GM_GOACTIVE and GM_HANDLEINPUT, the gadget can bitwise-OR any of
these "go inactive" return values with GMR_VERIFY.  The GMR_VERIFY flag
tells Intuition to send a GADGETUP @{"IntuiMessage" link ADCD_v1.2:Reference_Library/Libraries/Lib_9/9-5-4} to the gadget's window.
If the gadget uses GMR_VERIFY, it has to supply a value for the
@{"IntuiMessage.Code" link ADCD_v1.2:Reference_Library/Libraries/Lib_9/9-5-4 33} field.  It does this by passing a value in the
gpInput.gpi_Termination field.  This field points to a long word, the
lower 16-bits of which Intuition copies into the Code field.  The upper
16-bits are for future enhancements, so clear these bits.

@ENDNODE

@NODE 12-3-1-4 "12 / / The Boopsi Gadget Methods / GM_GOINACTIVE"
After an active gadget deactivates, Intuition sends it a GM_GOINACTIVE
message (defined in <intuition/@{"gadgetclass.h" link ADCD_v1.2:Inc&AD2.1/includes/intuition/gadgetclass.h/MAIN 161}>):

    struct gpGoInactive
    {
        ULONG             MethodID;    /* GM_GOINACTIVE */
        struct GadgetInfo *gpgi_GInfo;

        /* V37 field only!  DO NOT attempt to read under V36!          */
        ULONG             gpgi_Abort; /* gpgi_Abort=1 if gadget was    */
                                      /* aborted by Intuition          */
                                      /* and 0 if gadget went inactive */
                                      /* at its own request.           */
    };

The gpgi_Abort field contains either a 0 or 1.  If 0, the gadget became
inactive on its own power (because the @{"GM_GOACTIVE" link 12-3-1-3} or @{"GM_HANDLEINPUT" link 12-3-1-3 26}
method returned something besides @{"GMR_MEACTIVE" link 12-3-1-3 67}).  If gpgi_Abort is 1,
Intuition aborted this active gadget.  Some instances where Intuition
aborts a gadget include: the user clicked in another window or screen, an
application removed the active gadget with RemoveGList(),  and an
application called @{"ActiveWindow()" link ADCD_v1.2:Reference_Library/Libraries/Lib_4/4-3-3 19} on a window other than the gadget's
window.

@ENDNODE

@NODE 12-3-2 "12 / Boopsi Gadgets / The Active Gadget"
While a gadget is active, Intuition sends it a @{"GM_HANDLEINPUT" link 12-3-1} message for
every timer pulse, mouse move, mouse click, and key press that takes
place.  A timer event pulse arrives about every tenth of a second.  Mouse
move events can arrive at a much higher rate than the timer pulses.
Without even considering the keyboard, a gadget can get a lot of
GM_HANDLEINPUT messages in a short amount of time. Because the active
gadget has to handle a large volume of GM_HANDLEINPUT messages, the
overhead of this method should be kept to a minimum.

Because the gadget will always receive a @{"GM_GOACTIVE" link 12-3-1} message before it is
active and a @{"GM_GOINACTIVE" link 12-3-1} message after it is no longer active, the
gadget can use these methods to allocate, initialize, and deallocate
temporary resources it needs for the @{"GM_HANDLEINPUT" link 12-3-1} method.  This can
significantly reduce the overhead of GM_HANDLEINPUT because it eliminates
the need to allocate, initialize, and deallocate resources for every
GM_HANDLEINPUT message.

Note that the @{"RastPort" link ADCD_v1.2:Reference_Library/Libraries/Lib_27/27-4-1} from @{"ObtainGIRPort()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/ObtainGIRPort()} is not cachable using this
method.  If the @{"GM_HANDLEINPUT" link 12-3-1} method needs to use a RastPort, it has to
obtain and release the RastPort for every GM_HANDLEINPUT message using
ObtainGIRPort() and @{"ReleaseGIRPort()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/ReleaseGIRPort()}.

@{" RKMButtonclass.c " link 12-3-2-1}

@ENDNODE

@NODE 12-3-2-1 "12 / / The Active Gadget / RKMButtonclass.c"
The following example is a sample Boopsi gadget, RKMButClass.c.  While the
user has the RKMButton selected, the gadget sends an @{"OM_UPDATE" link 12-2-2 32} message to
its @{"ICA_TARGET" link 12-1-3 20} for every timer event the button sees.  The gadget sends
notification about its RKMBUT_Pulse attribute, which is the horizontal
distance in screen pixels the mouse is from the center of the button.  The
gadget takes care of rendering all of its imagery (as opposed to using a
Boopsi image to do it).  The gadget's imagery is scalable to any
dimensions and can be set (using @{"SetGadgetAttrs()" link 12-1-1-4 5}) while the gadget is in
place.

One possible use for such a gadget is as buttons for a prop gadget. If the
user has the prop gadget's RKMButton selected, while the mouse is to the
left of the button's center, the knob on the prop gadget moves left.
While the mouse is to the right of the button's center, the knob on the
prop gadget moves right.  The speed at which the knob moves is
proportional to the horizontal distance from the mouse to the active
RKMButton.

    @{" RKMButClass.c " link ADCD_v1.2:Reference_Library/Libraries/lib_examples/RKMButClass.c/MAIN}

@ENDNODE

@NODE 12-4 "12 Boopsi--Object Oriented Intuition / Function Reference"
The following are brief descriptions of the Intuition and amiga.lib
functions discussed in this chapter.  See the "Amiga ROM Kernel Reference
Manual: Includes and Autodocs" for details on each function call.  All
these functions require Release 2 or a later version of the Amiga
operating system.

              Table 12-1: Intuition Library Boopsi Functions
  ________________________________________________________________________
 |                                                                        |
 |       Function                 Description                             |
 |========================================================================|
 |      @{"NewObjectA()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/NewObject()}  Create a new Boopsi object (tag array form).        |
 |       @{"NewObject()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/NewObject()}  Create a new Boopsi object (varargs form).          |
 |   @{"DisposeObject()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/DisposeObject()}  Dispose of a Boopsi object.                         |
 |        @{"SetAttrs()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/SetAttrsA()}  Set one or more of a Boopsi object's attributes     |
 |                    (tag array form).                                   |
 |  @{"SetGadgetAttrs()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/SetGadgetAttrsA()}  Set one or more of a Boopsi object's attributes     |
 |                    (varargs form).                                     |
 |         @{"GetAttr()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/GetAttr()}  Obtain an attribute from a Boopsi object.           |
 |------------------------------------------------------------------------|
 |       @{"MakeClass()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/MakeClass()}  Create a new private or public Boopsi class.        |
 |       @{"FreeClass()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/FreeClass()}  Free a Boopsi class created by MakeClass().         |
 |        @{"AddClass()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/AddClass()}  Add a public Boopsi class to Intuition's internal   |
 |                    list of public classes.                             |
 |     @{"RemoveClass()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/RemoveClass()}  Remove a public Boopsi class that was added to      |
 |                    Intuition's internal list with AddClass().          |
 |------------------------------------------------------------------------|
 |   @{"ObtainGIRPort()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/ObtainGIRPort()}  Set up a @{"RastPort" link ADCD_v1.2:Reference_Library/Libraries/Lib_27/27-4-1} for use by a Boopsi gadget        |
 |                    dispatcher.                                         |
 |  @{"ReleaseGIRPort()" link ADCD_v1.2:Inc&AD2.1/autodocs/intuition/ReleaseGIRPort()}  Free a RastPort set up by ReleaseGIRPort().         |
 |________________________________________________________________________|


                  Table 12-2: Amiga.lib Boopsi Functions
  ________________________________________________________________________
 |                                                                        |
 |       Function                 Description                             |
 |========================================================================|
 |       @{"DoMethodA()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/DoMethodA()}  Send a Boopsi message to a Boopsi object            |
 |                    (tag array form).                                   |
 |        @{"DoMethod()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/DoMethod()}  Send a Boopsi message to a Boopsi object            |
 |                    (varargs form).                                     |
 |  @{"DoSuperMethodA()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/DoSuperMethodA()}  Send a Boopsi message to a Boopsi object as if the  |
 |                    object was an instance of its class's superclass    |
 |                    (tag array form).                                   |
 |   @{"DoSuperMethod()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/DoSuperMethod()}  Send a Boopsi message to a Boopsi object as if the  |
 |                    object was an instance of its class's superclass    |
 |                    (varargs form).                                     |
 |   @{"CoerceMethodA()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/CoerceMethodA()}  Send a Boopsi message to a Boopsi object as if the  |
 |                    object was an instance of the specified class       |
 |                    (tag array form).                                   |
 |    @{"CoerceMethod()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/CoerceMethod()}  Send a Boopsi message to a Boopsi object as if the  |
 |                    object was an instance of the specified class       |
 |                    (varargs form).                                     |
 |   @{"SetSuperAttrs()" link ADCD_v1.2:Inc&AD2.1/autodocs/amiga_lib/SetSuperAttrs()}  Send a Boopsi @{"OM_SET" link 12-2-2 28} message to the Boopsi object's |
 |                    superclass.                                         |
 |________________________________________________________________________|

@ENDNODE
