@c -*-texinfo-*-
@node AWS Custom Components, AWS Trigger Reference, AWS Signals, AWS
@subsection Creating Custom @sc{aws} Components

Obviously, the components included with @sc{aws} will not cover
every single user's needs. Or, you may not like the way a
certain control actually works. Maybe you want it to glow faintly
when the mouse is over it. Or perhaps you don't like the way
command buttons look. @sc{aws} is designed
to be simple for component designers to use and extend. Without a rich set
of components, no windowing system is very interesting.

The first thing you need to know is that all components are
derived from the common base class @samp{awsComponent}. This
component has built in handling for events and drawing. You
don't need to know anything about how internal event handling
happens; you just have to override the correct events. This base
component also has built in support for handling automatic
@dfn{parameter delivery}, and sinks and sources. The next few
sections detail the things that you should do to make a
good, robust, custom @sc{aws} component.

@menu
* AWS Component Parameter Delivery:: Parameter Delivery
* AWS Component Events:: Events: Responding To User Actions
* AWS Component Signals:: Sending and Receiving Signals
@end menu

@node AWS Component Parameter Delivery, AWS Component Events, AWS Custom Components, AWS Custom Components
@subsubsection Parameter Delivery

This section describes automatic @dfn{parameter delivery}, which provides a
mechanism for extracting component parameters from a window definition.

In @sc{aws}, all windows are defined by a window definition.
There may be multiple definitions in a file, or you may have
multiple files. That's all up to the end user. For a component
writer, however, you need to be able to get at this information.
Furthermore, you need to be able to get the information for the
window that's being created, and for the current instance of the
component. How does that happen?

It's very easy, actually. The window manager knows everything about everything,
and it particularly knows where the component is in the window's setup process.
You should only need to get your parameters once per creation of a window, and
that happens at setup time.

Each component @strong{must} override a function called @code{Setup()} in
@samp{awsComponent}. You should always called the base
@code{awsComponent::Setup()} first, because there is some important work for it
to do. You must never release or delete the parameters passed in to you,
because they are not yours. You should never store the settings parameter,
because it is only on loan and strange things may happen to it. Next, you are
free to do whatever setup your component needs. This is primarily accomplished
by using the @code{GetBlah()} functions of the preference manager. The
@code{Setup()}
function is passed two important parameters: a pointer to the window manager,
and a pointer to the current settings container that contains all the settings
for this instance of this component. The prototype for the setup function is
as follows:

@example
bool awsComponent::Setup(iAws* wmgr, awsComponentNode *settings)
@end example

The default @code{Setup()} in @samp{awsComponent} sets an internal variable
that stores the pointer to the window manager, which may then be retrieved
afterward from the accessor function @code{WindowManager()}.  The first
statement in a setup function should always be:

@example
if (!awsComponent::Setup(wmgr, settings))
  return false;
@end example

This lets the lower level setup code do some important initialization, and also
keeps us from proceeding if something cataclysmic happens during initial setup.
Returning @samp{false} from the @code{Setup()} function at any time gracefully
aborts construction of the component.  It does not, however, abort construction
of the entire container or window.  It @emph{does} abort construction of any
children this component may have.

After the initial call to the base version of @code{Setup()}, you may do
whatever you like. It is common to retrieve any important settings for your
component here. For example, the base @samp{awsComponent} retrieves the
component's frame rectangle by performing the following:

@example
iAwsPrefs *pm = WindowManager()->GetPrefMgr();
pm->GetRect(settings, "Frame", frame);
@end example

The preference manager supports two other versions of this
command, altogether providing @code{GetInt()}, @code{GetRect()},
and @code{GetString()}. The first parameter is always provided
for you: it is the settings container passed as a parameter. The
second parameter is the text name of the attribute you wish to
query, like @samp{Frame} or @samp{Style}, etc. The final
parameter is a variable of the type corresponding to the
function, in which the results will be stored. For
@code{GetInt()} this is always a signed integer, for
@code{GetRect()} this is a @samp{csRect} structure, and for
@code{GetString()} this is an @samp{iString} pointer.

If your component needs to get information about the default
skin, it can do so using some other, very similar functions for
the skin definition:

@itemize @bullet
@item
@code{LookupIntKey()}
@item
@code{LookupRectKey()}
@item
@code{LookupStringKey()}
@item
@code{LookupRGBKey()}
@end itemize

These functions operate in a fashion identical to the
@code{GetBlah()} functions, except that they know where their
information is coming from, so they don't need a settings
parameter. Also, @code{LookupRGBKey()} requires a reference to
three value parameters: red, green, and blue in that order. Each
is an unsigned character. Note that the preference manager also
supports a @code{Get()} for colors, textures, and fonts. It is
preferred to use these functions for actually getting those
resources for use. Please consult the @sc{api} reference for
@samp{awsPreferenceManager} for further information on those
functions.

Once you have finished your setup process, you should always
exit by returning @samp{true}. This means that everything went well and
you are ready to work.

@node AWS Component Events, AWS Component Signals, AWS Component Parameter Delivery, AWS Custom Components
@subsubsection Events: Responding To User Actions

Events are broken out into @code{OnBlah()} functions. The
parameters for those events are also broken out and passed to the
functions. At the end of any of the @code{OnBlah()} event
functions (except @code{OnDraw()}) you should return @samp{true} if the
event was used by you, otherwise return @samp{false}. You @emph{must}
override @emph{all} event functions, even if you don't use them
all. If you will not use a particular event, just return @samp{false}.

It's important to note that you will only receive events that
apply to your component. For example, if the mouse is inside
your component, you will receive all mouse events. However, once
the mouse leaves the confines of your borders you will no longer
receive @emph{any} mouse events. The only exception to this is
the @code{OnMouseExit()} event which is sent to the component that
just lost the mouse.

The following is the list of all events understood by components:

@table @code
@item virtual bool OnMouseDown(int button, int x, int y)
Triggered when the user presses a mouse button.

@item virtual bool OnMouseUp(int button, int x, int y)
Triggered when the user releases a mouse button.

@item virtual bool OnMouseMove(int button, int x, int y)
Triggered when the user moves the mouse.

@item virtual bool OnMouseClick(int button, int x, int y)
Triggered when the user clicks the mouse.

@item virtual bool OnMouseDoubleClick(int button, int x, int y)
Triggered when the user double clicks the mouse.

@item virtual bool OnMouseExit()
Triggered when this component loses mouse focus.

@item virtual bool OnMouseEnter()
Triggered when this component gains mouse focus.

@item virtual bool OnKeypress(int key, int modifiers)
Triggered when the user presses a key.

@item virtual bool OnLostFocus()
Triggered when the keyboard focus is lost.

@item virtual bool OnGainFocus()
Triggered when the keyboard focus is gained.
@end table

@node AWS Component Signals, , AWS Component Events, AWS Custom Components
@subsubsection Sending and Receiving Signals

@sc{aws} supports signal sources and sinks. A signal is simply a
bit of information that lets someone know that something
happened. A signal source is an object that gives out signals.
A signal sink is an object that receives them. A signal slot is
a conduit that manages a connection between sources and sinks.
All @sc{aws} components are signal sources. They are derived
from @samp{awsSource}, and thus support all the functionality of
that class.

Signals are very distinct from Events. Signals are usually not
sent for vents like @samp{MouseDown}, etc. A signal usually
indicates that something important happened to the source. Good
examples of signals are @samp{TextChanged} for a text-box or
@samp{ButtonClicked} for a command button. These indicate that
the user has gone through a series of complex motions, and has
triggered the component to do something that it was programmed
for. Signals do not include extra parameter information, simply a
32-bit value that indicates what happened.

Signals are unique to each component. Therefore, you never have
to worry about namespace conflicts. For instance, if you want notification
when a command button is clicked, you can connect your ``button clicked''
handler to the button like this:

@example
awsSlot slot(mySink);
slot.Connect(cmdbutton,
  awsButton::sButtonClicked,
  doSomethingUsefulTrigger);
@end example

The parameter to the slot is the class that contains your sink.
This can be any class derived from @samp{iAwsSink}. For the connect
call, the first parameter is the signal source that you are
connecting to, the second is the signal you want notification of, and
the final parameter is the identifier of the trigger you want activated
on the sink when signaled. A single slot can map between a
number of sources, signals, and triggers. To get the trigger identifier
(which may change every time your application is run) you merely
need to call @code{GetTriggerID()} on the sink with the name of the
trigger that you want.

@example
unsigned long trigger = mySink->GetTriggerID("LoginUser");
@end example

What this means is that you don't have to override the @samp{awsButton}
class to find out what's going on. In fact, you don't even have
to know about the button. All you need to know is that it
supports the signal. If it doesn't support the signal, by the
way, you will simply never get any information about it. Your slot will
never become active.

A slot maps back to a sink's trigger. A single slot is @emph{always}
bound to a single sink, but there may be other slots bound to the
same sink. When a trigger gets activated, it's passed in a
reference to the source of the signal. That way it can get any
information that it needs out of that source. A trigger could use
this information to find out what type of component the source is
and cast it to the correct type. The primary means for doing that
resides in the @code{GetProperty()} and @code{SetProperty} methods. These
allow you to request a property by name from a random component.
If the component does not support the property, the call will
fail in a graceful manner.
