\begindata{text,538947568} \textdsversion{12} \template{default} \define{global

advertisement
\begindata{text,538947568}
\textdsversion{12}
\template{default}
\define{global
}
\define{itemize
}
\formatnote{\chapter{Example 6:
Scroll bars}} \indexi{Scroll bars}
Example 6 illustrates how to create an object that has scroll bars. A
view
may not have been allocated enough screen space to be able to display its
entire area. Scroll bars allow users to change the portion of the view
that
is visible on the screen. The Andrew Toolkit contains a class,
\italic{scroll}, that provides bars for scrolling a view vertically and
horizontally. \indexi{Scroll} \indexi{Class++Scroll}
The example program in this section will build upon the program in
Example 5.
The program will have the same menu and keyboard functionality as
Example 5,
but will present the \italic{helloworldview} object with vertical and
horizontal scroll bars.
The discussion that follows presents a step-by-step description of how to
modify the \italic{helloworldview} class in Example 5 to produce Example
6.
If you were to follow the steps, you would produce a program, called
\italic{helloworldapp}, in five files:
\itemize{
a hellov.ch file -- will contain the class definition for helloworldview.
It
will be exactly the same as Example 5, except it will override view's
GetInterface method, the method that the scroll and helloworldview
objects
will use to communicate about the interface.
a hellov.c file -- will contain statements that import Andrew Toolkit
classes
and define the object's methods and class procedures. We will add methods
for
communicating with the scroll bar object.
a helloa.ch file -- will contain the class definition for the application
program that will display an instance of the class in a window. This will
be
exactly the same as in Example 5.
a helloa.c -- will contain declarations needed by the Andrew Toolkit
linking
and loading facilities as well the definition of the
\italic{helloworldview}
application method. We will include procedures to create the scroll bar,
and
modify the SetView call so that the scroll bar will be linked into the
view
tree.
Makefile -- will contain the directions for compiling, linking and
loading.
This will be exactly the same as Example 5.
}
For a complete listing of these files, see \italic{Program listing for
example
6} at the end of this section on p.
\begindata{textref,539314952}
\textdsversion{12}
# ExSixListing\
\enddata{textref,539314952}
\view{textrefv,539314952,897,0,0}.
The source code is available in the
directory /usr/andrew/examples/ex6.
Although the discussion of the steps refers directly to this example, the
information generally applies to the creation of any class that will use
scroll bars.
\begindata{bp,538929416}
\enddata{bp,538929416}
\view{bpv,538929416,898,0,0}
\section{Running the example program}
\formatnote{\formatnote{To run the program, at the \bold{command }prompt
type
\example{runapp /usr/andrew/examples/ex6/helloa}
and press the Enter key.
}
\bold{Response.}\formatnote{
\italic{hello world}
}The program will produce a window with
centered in the body of the window and a scroll bar on the left and on
the
bottom of the window as in Figure
\begindata{textref,539315976}
\textdsversion{12}
ex6\
\enddata{textref,539315976}
\view{textrefv,539315976,899,0,0}. Menu and key functionality is the
same as
in Example 5.
\bold{Action 2.}\formatnote{
}Drag one of the scroll bar elevators (the
white portion of the scroll bar) up or down using the mouse.
\bold{Response. }\formatnote{
}The string \italic{hello world} will be
drawn
in the window corresponding to the elevator movement, or the string will
disappear from the window completely if it is moved beyond the range of
the
visual rectangle.
}
\begindata{bp,538929736}
\enddata{bp,538929736}
\view{bpv,538929736,900,0,0}
\section{Overview of the scroll bar}\indexi{Scroll bars}
The scroll bar represents the entire view. The striped area at the top
of the
scroll bar column represents the beginning of the view; the striped area
at
the bottom, the end of the view. (If a window is very short, the striped
areas will not appear in the scroll bar.)
The white bar represents that portion of the view currently visible in
the
window and its location in the view. If the view is very long, the white
bar
will be small, because only a small portion of the view will be displayed
in
the window.
If the view is very short, the white bar will run the
length of
the scroll bar, indicating that the entire view is visible. If a user
adds or
removes information in a window, the white bar will change size to
reflect the
changes.
The black box inside the scroll bar indicates the location of some object
of
interest, for example, the text caret. In this example, it will indicate
the
location of the \italic{hello world} string.
More technically, the scroll bar allows the user to change the mapping
between
the coordinate system that the view uses internally and the visible
portion on
the screen. This mapping can be done in two dimensions--vertical and
horizontal, as in the \italic{helloworldview} example.
The scroll bar package queries the view for information it needs in order
to
represent the view. The scroll bar will get the following information
from
the view:
\itemize{
the view's range--the range that the entire scroll bar will represent,
i.e.,
the vertical or horizontal dimensions of the view. \indexi{Scroll
bars++View
range}
the view's visible range--the range that the elevator will represent,
i.e.,
the range of the view that is visible in the area allocated to its
display.
\indexi{Scroll bars++View visible range}
the view's dot--the range that the scroll bar's black rectangle should
represent. \indexi{Scroll bars++Dot}
}
In addition, the scroll bar controls the view by calling a procedure that
set
the view's frame, i.e., gives directions to the view to move its display
in
response to the user's manipulation of the scroll bar. The view must
provide
the procedures for allowing the scroll bar to get information from the
view
and to set the view's frame. \indexi{Frame} \indexi{Scroll bar++Frame}
In the view tree hierarchy, the scroll bar is the parent of the view it
is
scrolling. In this example, the \italic{im} view is the parent of the
\italic{scroll} which is the parent of the \italic{helloworldview}
object.
\indexi{Scroll bar++View tree hierarchy}
\begindata{bp,538271624}
\enddata{bp,538271624}
\view{bpv,538271624,901,0,0}
\section{Modifying the class definition}
\subsection{Declaring the class}
If you are creating a subclass of view that will be scrollable, you must
override view's \italic{GetInterface} \indexi{ \italic{GetInterface}}
\indexi{ \italic{view_GetInterface}}
\indexi{Methods++\italic{GetInterface}}
method. This method provides a way for the scroll bar to communicate
with the
view about user's scrolling requests.
In addition, you will want to add at least two new elements to the data
structure. The first must hold the (x,y) offset from the top left of the
view's displayed image to the top left of the view's visual rectangle. A
second must hold new (x,y) offset pending an update.
The following is the new class declaration for the example class
\italic{helloworldview}:
\formatnote{
class helloworldview [hellov]: view \{
overrides:
FullUpdate(enum view_UpdateType type, long left, long top, long
width,
long height);
Update();
Hit (enum view_MouseAction action, long x, long y, long
numberOfClicks)
returns struct view *;
ReceiveInputFocus();
LoseInputFocus();
\bold{GetInterface(int type) returns char *;}
classprocedures:
InitializeClass() returns boolean;
data:
struct keystate *keystate;
struct menulist *menulist;
boolean HaveDownTransition;
boolean haveInputFocus;
long x,y;
long distX,distY;
boolean blackOnWhite;
long newX,newY;
boolean newBlackOnWhite;
\bold{long frameX, frameY;
long newFrameX, newFrameY;
int vrWidth,vrHeight;}
\};
}
Example 6's \italic{helloworldview} overrides view's
\italic{GetInterface}
method. It will store the (x,y) offset in (\italic{frameX},
\italic{frameY})
and the new offset pending an update in (\italic{newFrameX},
\italic{newFrameY}). Finally, \italic{vrWidth} and \italic{vrHeight}
will
hold the width and height of \italic{helloworldview}'s visual rectangle,
simply to avoid the need to recalculate them.
\begindata{bp,538928968}
\enddata{bp,538928968}
\view{bpv,538928968,902,0,0}
\subsection{The scroll bar interface} \indexi{Scroll bars++Interface}
The scroll bar interface consists of a set of four function pointers that
the
scroll bar will call in order to get information about the view that it
is
scrolling and to control the view. The interface is defined by a
structure
\italic{scrollfns} (scroll functions )that contains four "function"
pointers:
\indexi{Scroll bars++Scroll functions}
\itemize{
a pointer to a routine that returns state information about the view
\italic{SetFrame}--a pointer to a routine that positions the view
according to
parameters specified by the scrollbar \indexi{ \italic{SetFrame}}
\italic{EndZone}--a pointer to a routine that positions the view when the
user
clicks in the end zones of the scrollbar. \indexi{ \italic{EndZone}}
\italic{WhatIsAt}--a pointer to a routine that returns information about
position \indexi{ \italic{WhatIsAt}}
}
For each axis (vertical or horizontal) that you want to be scrollable,
you
must declare a scroll bar interface structure and define a set of four
interface routines. The names of the routines are arbitrary, but the
parameters and actions that they perform are not.
For example, the following declares a scroll bar interface for
\italic{helloworldview} from hellov.c:
\formatnote{
static void xgetinfo(), xsetframe(), ygetinfo(), ysetframe();
static long xwhat(), ywhat();
static struct scrollfns horizInterface = \{
xgetinfo, xsetframe, NULL, xwhat
\};
static struct scrollfns vertInterface = \{
ygetinfo, ysetframe, NULL, ywhat
\};
}
In the \italic{helloworldview} object, the routines pointed to by
\italic{horizInterface} are used to maintain the horizontal scrollbar,
and
\italic{vertInterface}, the vertical one.
\paragraph{The interface routine for getting state information}
\indexi{Scroll bars++State information}
\indexi{ \italic{Getinfo}}
The scroll bar will call a view's getinfo routine when it needs to know
about
the state of the view. Your \italic{getinfo} routine should set the
state
information for the ranges \italic{total}, \italic{seen}, and
\italic{dot.}
Each of these consists of two fields: \italic{beg}, the beginning of
the
range, and \italic{end}, its end. A general structure looks as follows:
\formatnote{
static void getinfo(v, total, seen, dot)
struct view *v;
struct range *total, *seen, *dot;
}
\itemize{
\italic{Total} is the the range that the entire scrollbar represents.
You
should set the beginning of the range to 0 and end of the range to the
width
or height of the entire view.
\italic{Seen} is the range that the elevator represents. You should set
the
beginning of the range to the view's top-left visual coordinates; the
end to
the bottom-right visual coordinates.
\italic{Dot} is the range that the black rectangle represents, usually
something that is selected, or the point of current interest.
}
In this example program, \italic{helloworldview} provides two routines
that
provide state information, \italic{xgetinfo} for the horizontal scroll
bar and
\italic{ygetinfo} for the vertical. The names of the routines are
arbitrary,
but they must correspond to the names declared in the scroll bar
interface
declaration.
\formatnote{
static void xgetinfo(hwv, total, seen, dot)
struct helloworldview *hwv;
struct range *total, *seen, *dot;
\{
total->beg = 0;
total->end = TOTALSIZE;
seen->beg = hwv->frameX;
seen->end = hwv->frameX + hwv->vrWidth;
dot->beg = dot->end = hwv->x;
\}
static void ygetinfo(hwv, total, seen, dot)
struct helloworldview *hwv;
struct range *total, *seen, *dot;
\{
total->beg = 0;
total->end = TOTALSIZE;
seen->beg = hwv->frameY;
seen->end = hwv->frameY + hwv->vrHeight;
dot->beg = dot->end = hwv->y;
\}
}
In \italic{xgetinfo}, the statements \italic{total->beg = 0} and
\italic{total->end = \smaller{TOTALSIZE}} sets the range total to the
range of
the helloworldview coordinate space (which in this example is fixed,
ranging
from 0 to \smaller{TOTALSIZE}).
The statements \italic{seen->beg = hwv->frameX} and \italic{seen->end =
hwv->frameX + hwv->vrWidth} sets the range seen to
\italic{helloworldview}'s
visual rectangle, the portion displayed on the screen from the edge in
(frameX, frameY) extending for the (width, height) of the view.
The statement \italic{dot->beg = dot->end = hwv->x} simply sets the range
dot
to the position of the \italic{hello world} string within total; because
it
has zero size, the black marker in the scrollbar will simply reflect the
position (not the size) of the \italic{hello world} string.
The routine \italic{ygetinfo} is analogous to \italic{xgetinfo}.
\begindata{bp,538929224}
\enddata{bp,538929224}
\view{bpv,538929224,903,0,0}
\paragraph{Setting the view's frame upon user's scrolling requests}
The setframe routine gets called whenever scrolling occurs, and should
set the
view in its frame so that it's position reflects the new position of the
scrollbar. It tells \italic{view} to move its display (and remember,
this
should all happen only in the particular axis which is being scrolled by
this
routine) so that \italic{position}, in its own coordinate system (its
\italic{total} range, as given to the\italic{ getinfo} call), is located
at a
pixel offset of \italic{coordinate}; \italic{outof} is the total number
of
pixels in this axis of the view, so \italic{coordinate}/\italic{outof} is
the
fraction from the edge of \italic{view} where the \italic{position}'s
coordinate should be moved to.
\indexi{Scroll bars++Frame}
\indexi{ \italic{SetFrame}}
The following is the general structure of the \italic{setframe} routine:
\formatnote{
static void setframe(v, posn, coord, outof)
struct view *v;
int posn;
long coord, outof;
}
\italic{helloworldview} provides two routines that set the frame,
\italic{xsetframe} for the horizontal scroll bar and \italic{ysetframe}
for
the vertical. The names of the routines are arbitrary, but they must
correspond to the names declared in the scroll bar interface declaration.
\formatnote{
static void xsetframe(hwv, posn, coord, outof)
struct helloworldview *hwv;
int posn;
long coord, outof;
\{
hwv->newFrameX = posn - hwv->vrWidth * coord / outof;
if (hwv->newFrameX + hwv->vrWidth > TOTALSIZE)
hwv->newFrameX = TOTALSIZE - hwv->vrWidth;
else if (hwv->newFrameX < 0)
hwv->newFrameX = 0;
helloworldview_WantUpdate(hwv, hwv);
\}
static void ysetframe(hwv, posn, coord, outof)
struct helloworldview *hwv;
int posn;
long coord, outof;
\{
hwv->newFrameY = posn - hwv->vrHeight * coord / outof;
if (hwv->newFrameY + hwv->vrHeight > TOTALSIZE)
hwv->newFrameY = TOTALSIZE - hwv->vrHeight;
else if (hwv->newFrameY < 0)
hwv->newFrameY = 0;
helloworldview_WantUpdate(hwv, hwv);
\}
}
In \italic{xsetframe}, the statements \italic{hwv->newFrameX = posn hwv->vrWidth * coord / outof} positions point \italic{posn} at
\italic{coord}/\italic{outof} from the top, left edge of the view. The
\italic{if/else if} statement simply checks that the resulting position
is
within \italic{hwv}'s range. The routine \italic{ysetframe} is
analogous.
\paragraph{A routine to manage endzone hits}
\indexi{Scroll bars++Endzone hits}
\indexi{ \italic{Endzone}}
The following is the general structure of the endzone routine:
\formatnote{
static void endzone(v, zone, action)
struct view *v;
int zone;
enum view_MouseAction action;
}
The endzone routine gets called when the user clicks in the scrollbar
endzone;
\italic{zone} is either \smaller{scroll_TOPENDZONE} or
\smaller{scroll_BOTTOMENDZONE}, for the top or bottom zone, and
\italic{action}
is how the user clicked (enum view_MouseAction, see View, Vol. 2). If
the
pointer to this procedure in the \italic{scrollfns} structure is
\smaller{NULL}, this procedure defaults to scrolling the view to the
beginning/end. This is the case in the \italic{helloworldview} example,
therefore the routine is not included explicitly.
\paragraph{Finding the coordinates of the string}
\indexi{Scroll bars++String coordinates}
\indexi{ \italic{Whatisat}}
\formatnote{
static long whatisat(v, coord, outof)
struct view *v;
long coord;
long outof;
}
This routine should return the coordinate (in the total range of the
particular axis of \italic{view}), of what is located at the
\italic{coordinate}'s pixel (out of \italic{outof} total pixels).
In the helloworldview view, we define two sets of routines to correspond
to
these, one for each axis, to give to the scrolling code.
\formatnote{
static long xwhat(hwv, coord, outof)
struct helloworldview *hwv;
long coord, outof;
\{
return hwv->frameX + hwv->vrWidth * coord / outof;
\}
static long ywhat(hwv, coord, outof)
struct helloworldview *hwv;
long coord, outof;
\{
return hwv->frameY + hwv->vrHeight * coord / outof;
\}
}
In \italic{xwhat}, the statement \italic{return hwv->frameX + hwv>vrWidth *
coord / outof} returns what's coord/outof from the edge of the view,
\italic{hwv}.
The routine \italic{ywhat} is analogous.
\begindata{bp,538929288}
\enddata{bp,538929288}
\view{bpv,538929288,904,0,0}
\subsection{Initializing the helloworldview object}
\indexi{Objects++Initializing}
\indexi{ \italic{InitializeObject}}
\formatnote{
boolean helloworldview__InitializeObject(classID, hwv)
struct classheader *classID;
struct helloworldview *hwv;
\{
hwv->x = POSUNDEF;
hwv->y = POSUNDEF;
hwv->HaveDownTransition = FALSE;
hwv->haveInputFocus = FALSE;
hwv->keystate = keystate_Create(hwv, helloworldviewKeymap);
hwv->blackOnWhite = TRUE;
hwv->newBlackOnWhite = TRUE;
hwv->menulist = menulist_DuplicateML(helloworldviewMenulist, hwv);
\bold{hwv->newFrameX = hwv->newFrameY = 0;}
return TRUE;
}
The \italic{InitializeObject} procedure is exactly the same as Example5,
except that\italic{ frameX} and \italic{frameY} must be initialized also.
They are initialized to 0, so that the \italic{helloworldview} will
initially
display the top, leftmost corner of \italic{helloworldview}'s coordinate
system.
\subsection{Displaying the 'hello world' string}
The major difference in displaying the \italic{hello world} string from
the
previous example is that the position of the string within the view can
now
change without the the string's position in its own coordinate space
changing.
We calculate the screen position, which is the difference between the
internal position of the string and the offset of the the edge of the
view
from the origin of the internal coordinate system, and display the
string. It
is not necessary to make sure the string is actually visible, because a
view's
output is automatically clipped to the boundary of the rectangle
allocated for
it.
\paragraph{The full update procedure} \indexi{Full update}
\formatnote{
void helloworldview__FullUpdate(hwv, type, left, top, width, height)
struct helloworldview *hwv;
enum view_UpdateType type;
long left;
long top;
long width;
long height;
\{
struct rectangle myVisualRect;
helloworldview_GetVisualBounds(hwv,&myVisualRect);
hwv->vrWidth=rectangle_Width(&myVisualRect);
hwv->vrHeight=rectangle_Height(&myVisualRect);
if (hwv->newFrameX + hwv->vrWidth > TOTALSIZE)
hwv->newFrameX = TOTALSIZE - hwv->vrWidth;
if (hwv->newFrameY + hwv->vrHeight > TOTALSIZE)
hwv->newFrameY = TOTALSIZE - hwv->vrHeight;
hwv->frameX = hwv->newFrameX;
hwv->frameY = hwv->newFrameY;
if (hwv->x == POSUNDEF)
\{
hwv->x = hwv->frameX + hwv->vrWidth / 2;
hwv->y = hwv->frameY + hwv->vrHeight / 2;
hwv->newX = hwv->x;
hwv->newY = hwv->y;
\}
else \{
hwv->x = hwv->newX;
hwv->y = hwv->newY;
\}
helloworldview_SetTransferMode(hwv, graphic_COPY);
if (hwv->blackOnWhite)
\{
helloworldview_FillRect(hwv, &myVisualRect,
helloworldview_WhitePattern(hwv));
\}
else
\{
helloworldview_FillRect(hwv, &myVisualRect,
helloworldview_BlackPattern(hwv));
\}
helloworldview_SetTransferMode(hwv, graphic_INVERT);
helloworldview_MoveTo(hwv, hwv->x - hwv->frameX, hwv->y - hwv>frameY);
helloworldview_DrawString(hwv,"hello world",
graphic_BETWEENTOPANDBASELINE
| graphic_BETWEENLEFTANDRIGHT);
\}
}
The first set of tests make sure that the viewed portion of the
\italic{helloworldview} space does not extend past its edge, and if it
does,
adjusts the left/top boundary so that the right/bottom edge of the view
corresponds exactly with the right/bottom edge of the helloworldview
space.
Thus, there is never a question of a negative (newFrameX, newFrameY)
even if
the TOTALSIZE is smaller than the visual rectangle.
The check of \italic{hwv->x} against \smaller{POSUNDEF} centers the
string
within the currently viewed portion, and the \italic{MoveTo} before the
actual
display of the string takes the coordinate mapping into account, as
described
above.
\paragraph{The update procedure} \indexi{Update}
The changes to the \italic{Update} method are essentially the same as
those to
the \italic{FullUpdate} method. It must also test whether (frameX,
frameY)
have changed, and update if this has happened.
\formatnote{
void helloworldview__Update(hwv)
struct helloworldview *hwv;
\{
if (hwv->newBlackOnWhite != hwv->blackOnWhite) \{
struct rectangle vr;
helloworldview_GetVisualBounds(hwv,&vr);
helloworldview_FillRect(hwv, &vr,
helloworldview_BlackPattern(hwv));
hwv->blackOnWhite = hwv->newBlackOnWhite;
\}
\bold{if (hwv->newX != hwv->x || hwv->frameX != hwv->newFrameX ||
hwv->newY
!= hwv->y || hwv->frameY != hwv->newFrameY) }\{
helloworldview_MoveTo(hwv, hwv->x - hwv->frameX, hwv->y - hwv>frameY);
helloworldview_DrawString(hwv, "hello world",
graphic_BETWEENTOPANDBASELINE
| graphic_BETWEENLEFTANDRIGHT);
hwv->x = hwv->newX;
hwv->y = hwv->newY;
\bold{hwv->frameX = hwv->newFrameX;
hwv->frameY = hwv->newFrameY;
helloworldview_MoveTo(hwv, hwv->x - hwv->frameX, hwv->y hwv->frameY);}
helloworldview_DrawString(hwv, "hello world",
graphic_BETWEENTOPANDBASELINE| graphic_BETWEENLEFTANDRIGHT);
\}
\}
}
\subsection{Getting the scroll bar interface} \indexi{Scroll
bar++Interface}
\indexi{ \italic{GetInterface}}
\indexi{ \italic{view_GetInterface}}
The GetInterface method is what the scrollbar calls to get the pointers
to the
above scroll bar interface routines. As described in the beginning, we
have
already packed them into two \italic{scrollfns} structures. We just have
to
check what is being asked for (which is specified by the \italic{type}
string), and return it when appropriate.
\formatnote{
char *helloworldview__GetInterface(hwv, type)
struct helloworldview *hwv;
char *type;
\{
if (strcmp(type, "scroll,vertical") == 0)
return (char *) &vertInterface;
else if (strcmp(type, "scroll,horizontal") == 0)
return (char *) &horizInterface;
else
return NULL;
\}
}
\section{Creating the stand-alone program}
\subsection{Importing Andrew Toolkit classes} \indexi{Importing}
\formatnote{
#include <class.h>
#include "hellov.eh"
#include "graphic.ih"
#include "rect.h"
#include "keymap.ih"
#include "keystate.ih"
#include "menulist.ih"
#include "bind.ih"
\bold{#include "scroll.ih"}
}
\italic{scroll.ih} is also included to import the structures used to
interface
with the scrolling package.
\subsection{Creating an instance of a scroll}
\indexi{Scroll bars++Creating an instance}
\indexi{ \italic{Start}}
\formatnote{
#include <class.h>
#include "helloa.eh"
#include "im.ih"
\bold{#include "scroll.ih"}
#include "hellov.ih"
boolean helloworldapp__Start(hwapp)
struct helloworldapp *hwapp;
\{
struct helloworldview *hwv;
struct im *im;
\bold{struct scroll *scroll;}
if(!super_Start(hwapp))
return FALSE;
hwv=helloworldview_New();
if(hwv==NULL)
return FALSE;
\bold{scroll=scroll_Create(hwv,scroll_LEFT|scroll_BOTTOM);
if(scroll==NULL)\{
helloworldview_Destroy(hwv);
return FALSE;
\}}
im=im_Create(NULL);
if(im==NULL)\{
helloworldview_Destroy(hwv);
scroll_Destroy(scroll);
return FALSE;
\}
\bold{im_SetView(im,scroll);}
helloworldview_WantInputFocus(hwv,hwv);
return TRUE;
\}
}
In addition to the helloworldview and im structures, we must declare the
scroll bar structure, with \italic{struct scroll *scroll}. Then, after
we
create the new view, we create the scroll bar. The scroll_Create
\indexi{ \italic{scroll_Create}}
procedure creates a scroll object for the view, \italic{hwv.} The object
has
two scroll bars, one on the left and one at the bottom. In addition, it
makes
\italic{scroll} the parent of \italic{hwv}.
After the scroll bar has been created, we can create the im associated
with
this application. Finally, \italic{im_SetView (im, scroll)}
\indexi{Scroll bars++View tree hierarchy}
sets \italic{scroll} in the view tree with \italic{im} as its parent.
Thus,
\italic{im} is the parent of \italic{scroll} which is the parent of
\italic{hwv}.
Each creation method (e.g. helloworldview_New, scroll_Create) tests the
object
to be created against NULL, so that if the Interaction Manager did not
succeed
in creating that object, all previously created objects are explicitly
destroyed with the appropriate Destroy method, and a FALSE is returned to
alert the failure. This check is not absolutely necessary, but it is a
useful
construction for complex codes involving large numbers of objects.
\begindata{bp,538929032}
\enddata{bp,538929032}
\view{bpv,538929032,905,0,0}
\begindata{texttag,539236104}
\textdsversion{12}
ExSixListing\
\enddata{texttag,539236104}
\view{texttagv,539236104,906,0,0}
\section{Program listing for Example 6}
\formatnote{
\bold{hellov.ch}
class helloworldview[hellov] : view \{
overrides:
FullUpdate(enum view_UpdateType type, long left, long top, long
width,
long height);
Update();
Hit (enum view_MouseAction action, long x, long y, long
numberOfClicks)
returns struct view *;
ReceiveInputFocus();
LoseInputFocus();
GetInterface(int type) returns char *;
classprocedures:
InitializeClass() returns boolean;
data:
struct keystate *keystate;
struct menulist *menulist;
boolean HaveDownTransition;
boolean haveInputFocus;
long x,y;
long distX,distY;
boolean blackOnWhite;
long newX,newY;
boolean newBlackOnWhite;
long frameX, frameY;
long newFrameX, newFrameY;
int vrWidth,vrHeight;
\};
\bold{hellov.c}
#include <class.h>
#include "hellov.eh"
#include "graphic.ih"
#include "rect.h"
#include "keymap.ih"
#include "keystate.ih"
#include "menulist.ih"
#include "bind.ih"
#include "scroll.ih"
#define POSUNDEF -1
#define TOTALSIZE 1500
static void xgetinfo(), xsetframe(), ygetinfo(), ysetframe();
static long xwhat(), ywhat();
static struct scrollfns horizInterface = \{
xgetinfo, xsetframe, NULL, xwhat
\};
static struct scrollfns vertInterface = \{
ygetinfo, ysetframe, NULL, ywhat
\};
static struct keymap *helloworldviewKeymap;
static struct menulist *helloworldviewMenulist;
boolean helloworldview__InitializeObject(classID, hwv)
struct classheader *classID;
struct helloworldview *hwv;
\{
hwv->x = POSUNDEF;
hwv->y = POSUNDEF;
hwv->HaveDownTransition = FALSE;
hwv->haveInputFocus = FALSE;
hwv->keystate = keystate_Create(hwv, helloworldviewKeymap);
hwv->blackOnWhite = TRUE;
hwv->newBlackOnWhite = TRUE;
hwv->menulist = menulist_DuplicateML(helloworldviewMenulist, hwv);
hwv->newFrameX = hwv->newFrameY = 0;
return TRUE;
\}
void helloworldview__FullUpdate(hwv, type, left, top, width, height)
struct helloworldview *hwv;
enum view_UpdateType type;
long left;
long top;
long width;
long height;
\{
struct rectangle myVisualRect;
helloworldview_GetVisualBounds(hwv,&myVisualRect);
hwv->vrWidth=rectangle_Width(&myVisualRect);
hwv->vrHeight=rectangle_Height(&myVisualRect);
if (hwv->newFrameX + hwv->vrWidth > TOTALSIZE)
hwv->newFrameX = TOTALSIZE - hwv->vrWidth;
if (hwv->newFrameY + hwv->vrHeight > TOTALSIZE)
hwv->newFrameY = TOTALSIZE - hwv->vrHeight;
hwv->frameX = hwv->newFrameX;
hwv->frameY = hwv->newFrameY;
if (hwv->x == POSUNDEF)
\{
hwv->x = hwv->frameX + hwv->vrWidth / 2;
hwv->y = hwv->frameY + hwv->vrHeight / 2;
hwv->newX = hwv->x;
hwv->newY = hwv->y;
\}
else \{
hwv->x = hwv->newX;
hwv->y = hwv->newY;
\}
helloworldview_SetTransferMode(hwv, graphic_COPY);
if (hwv->blackOnWhite)
\{
helloworldview_FillRect(hwv, &myVisualRect,
helloworldview_WhitePattern(hwv));
\}
else
\{
helloworldview_FillRect(hwv, &myVisualRect,
helloworldview_BlackPattern(hwv));
\}
helloworldview_SetTransferMode(hwv, graphic_INVERT);
helloworldview_MoveTo(hwv, hwv->x - hwv->frameX, hwv->y - hwv>frameY);
helloworldview_DrawString(hwv,"hello world",
graphic_BETWEENTOPANDBASELINE
| graphic_BETWEENLEFTANDRIGHT);
\}
void helloworldview__Update(hwv)
struct helloworldview *hwv;
\{
/* TransferMode is graphic_INVERT from the last FullUpdate */
if (hwv->newBlackOnWhite != hwv->blackOnWhite)
\{
struct rectangle vr;
helloworldview_GetVisualBounds(hwv,&vr);
helloworldview_FillRect(hwv, &vr,
helloworldview_BlackPattern(hwv));
hwv->blackOnWhite = hwv->newBlackOnWhite;
\}
if (hwv->newX != hwv->x || hwv->frameX != hwv->newFrameX || hwv->newY
!=
hwv->y || hwv->frameY != hwv->newFrameY) \{
helloworldview_MoveTo(hwv, hwv->x - hwv->frameX, hwv->y - hwv>frameY);
helloworldview_DrawString(hwv, "hello world",
graphic_BETWEENTOPANDBASELINE |
graphic_BETWEENLEFTANDRIGHT);
hwv->x = hwv->newX;
hwv->y = hwv->newY;
hwv->frameX = hwv->newFrameX;
hwv->frameY = hwv->newFrameY;
helloworldview_MoveTo(hwv, hwv->x - hwv->frameX, hwv->y - hwv>frameY);
helloworldview_DrawString(hwv, "hello world",
graphic_BETWEENTOPANDBASELINE |
graphic_BETWEENLEFTANDRIGHT);
\}
\}
struct view *helloworldview__Hit(hwv, action, x, y, numberOfClicks)
struct helloworldview *hwv;
enum view_MouseAction action;
long x;
long y;
long numberOfClicks;
\{
if(hwv->HaveDownTransition)
switch(action)\{
case view_RightUp:
hwv->HaveDownTransition=FALSE;
/* fall through */
case view_RightMovement:
hwv->newX=x-hwv->distX;
hwv->newY=y-hwv->distY;
break;
case view_LeftUp:
hwv->HaveDownTransition=FALSE;
hwv->newX=x;
hwv->newY=y;
break;
case view_LeftMovement:
/* do nothing */
break;
default:
/* re-synchronize mouse */
hwv->HaveDownTransition=FALSE;
\}
if(!hwv->HaveDownTransition)
switch(action)\{
case view_RightDown:
hwv->distX=x-hwv->x;
hwv->distY=y-hwv->y;
/* fall through */
case view_LeftDown:
hwv->HaveDownTransition=TRUE;
helloworldview_WantInputFocus(hwv,hwv);
break;
\}
helloworldview_WantUpdate(hwv,hwv);
return (struct view *)hwv;
\}
void helloworldview__ReceiveInputFocus(hwv)
struct helloworldview *hwv;
\{
hwv->haveInputFocus = TRUE;
hwv->keystate->next = NULL;
helloworldview_PostKeyState(hwv, hwv->keystate);
helloworldview_PostMenus(hwv, hwv->menulist);
\}
void helloworldview__LoseInputFocus(hwv)
struct helloworldview *hwv;
\{
hwv->haveInputFocus = FALSE;
\}
static void Center(hwv, rock)
struct helloworldview *hwv;
long rock;
\{
hwv->newX = hwv->newFrameX + hwv->vrWidth / 2;
hwv->newY = hwv->newFrameY + hwv->vrHeight / 2;
helloworldview_WantUpdate(hwv, hwv);
\}
static void Invert(hwv, rock)
struct helloworldview *hwv;
long rock;
\{
hwv->newBlackOnWhite = ! hwv->newBlackOnWhite;
helloworldview_WantUpdate(hwv, hwv);
\}
static void xgetinfo(hwv, total, seen, dot)
struct helloworldview *hwv;
struct range *total, *seen, *dot;
\{
total->beg = 0;
total->end = TOTALSIZE;
seen->beg = hwv->frameX;
seen->end = hwv->frameX + hwv->vrWidth;
dot->beg = dot->end = hwv->x;
\}
static void ygetinfo(hwv, total, seen, dot)
struct helloworldview *hwv;
struct range *total, *seen, *dot;
\{
total->beg = 0;
total->end = TOTALSIZE;
seen->beg = hwv->frameY;
seen->end = hwv->frameY + hwv->vrHeight;
dot->beg = dot->end = hwv->y;
\}
static void xsetframe(hwv, posn, cord, outof)
struct helloworldview *hwv;
int posn;
long cord, outof;
\{
hwv->newFrameX = posn - hwv->vrWidth * cord / outof;
if (hwv->newFrameX + hwv->vrWidth > TOTALSIZE)
hwv->newFrameX = TOTALSIZE - hwv->vrWidth;
else if (hwv->newFrameX < 0)
hwv->newFrameX = 0;
helloworldview_WantUpdate(hwv, hwv);
\}
static void ysetframe(hwv, posn, cord, outof)
struct helloworldview *hwv;
int posn;
long cord, outof;
\{
hwv->newFrameY = posn - hwv->vrHeight * cord / outof;
if (hwv->newFrameY + hwv->vrHeight > TOTALSIZE)
hwv->newFrameY = TOTALSIZE - hwv->vrHeight;
else if (hwv->newFrameY < 0)
hwv->newFrameY = 0;
helloworldview_WantUpdate(hwv, hwv);
\}
static long xwhat(hwv, cord, outof)
struct helloworldview *hwv;
long cord, outof;
\{
return hwv->frameX + hwv->vrWidth * cord / outof;
\}
static long ywhat(hwv, cord, outof)
struct helloworldview *hwv;
long cord, outof;
\{
return hwv->frameY + hwv->vrHeight * cord / outof;
\}
char *helloworldview__GetInterface(hwv, type)
struct helloworldview *hwv;
char *type;
\{
if (strcmp(type, "scroll,vertical") == 0)
return (char *) &vertInterface;
else if (strcmp(type, "scroll,horizontal") == 0)
return (char *) &horizInterface;
else
return NULL;
\}
static struct bind_Description helloworldviewBindings[]=\{
\{"helloworld-center", "\\003",0, "Hello World,Center",0,0, Center,
"Center the helloworld string."\},
\{"helloworld-invert", "\\011",0, "Hello World,Invert",0,0, Invert,
"Invert the helloworld string."\},
NULL
\};
boolean helloworldview__InitializeClass(classID)
struct classheader *classID;
\{
helloworldviewMenulist=menulist_New();
helloworldviewKeymap=keymap_New();
bind_BindList(helloworldviewBindings,
helloworldviewKeymap,helloworldviewMenulist,
&helloworldview_classinfo);
return TRUE;
\}
\begindata{bp,538928712}
\enddata{bp,538928712}
\view{bpv,538928712,907,0,0}
\bold{helloa.ch}
class helloworldapp [helloa]: application[app]\{
overrides:
Start() returns boolean;
\};
\bold{helloa.c}
#include <class.h>
#include "helloa.eh"
#include "im.ih"
#include "scroll.ih"
#include "hellov.ih"
boolean helloworldapp__Start(hwapp)
struct helloworldapp *hwapp;
\{
struct helloworldview *hwv;
struct im *im;
struct scroll *scroll;
if(!super_Start(hwapp))
return FALSE;
hwv=helloworldview_New();
if(hwv==NULL)
return FALSE;
scroll=scroll_Create(hwv,scroll_LEFT|scroll_BOTTOM);
if(scroll==NULL)\{
helloworldview_Destroy(hwv);
return FALSE;
\}
im=im_Create(NULL);
if(im==NULL)\{
helloworldview_Destroy(hwv);
scroll_Destroy(scroll);
return FALSE;
\}
im_SetView(im,scroll);
helloworldview_WantInputFocus(hwv,hwv);
return TRUE;
\}
\bold{Makefile}
SRCDIR=/usr/andrew/
INCLUDES= -I. -I$\{SRCDIR\}include/atk -I$\{SRCDIR\}include
INCLUDESRC = $\{SRCDIR\}include/atk
CC=cc
DEBUG = -g
TOOLS = $\{SRCDIR\}bin/
CFLAGS= $\{DEBUG\} $\{INCLUDES\}
CLASSFLAGS=$\{INCLUDES\}
MAKEDO = $\{TOOLS\}makedo $\{DEBUG\} -b $\{TOOLS\} -d $\{SRCDIR\}lib
CLASS = $\{TOOLS\}class
.SUFFIXES: .ih .eh .ch .do
.ch.ih:
$\{CLASS\} $\{CLASSFLAGS\} $*.ch
.ch.eh:
$\{CLASS\} $\{CLASSFLAGS\} $*.ch
.o.do:
$\{MAKEDO\} $<
all:
helloa.do hellov.do
helloa.do: helloa.o helloa.eh
hellov.do: hellov.o hellov.eh
helloa.o: helloa.c
helloa.o: $\{INCLUDESRC\}/app.ih
helloa.o: $\{INCLUDESRC\}/graphic.ih
helloa.o: $\{INCLUDESRC\}/im.ih
helloa.o: $\{INCLUDESRC\}/observe.ih
helloa.o: $\{INCLUDESRC\}/point.h
helloa.o: $\{INCLUDESRC\}/rect.h
helloa.o: $\{INCLUDESRC\}/view.ih
helloa.o: $\{SRCDIR\}include/class.h
helloa.o: hellov.ih
helloa.o: helloa.eh
helloa.eh helloa.ih: helloa.ch
helloa.eh helloa.ih: $\{INCLUDESRC\}/app.ih
hellov.o: hellov.c
hellov.o: $\{INCLUDESRC\}/graphic.ih
hellov.o: $\{INCLUDESRC\}/observe.ih
hellov.o: $\{INCLUDESRC\}/point.h
hellov.o: $\{INCLUDESRC\}/rect.h
hellov.o: $\{INCLUDESRC\}/view.ih
hellov.o: $\{SRCDIR\}include/class.h
hellov.o: hellov.eh
hellov.eh hellov.ih: hellov.ch
hellov.eh hellov.ih: $\{INCLUDESRC\}/graphic.ih
hellov.eh hellov.ih: $\{INCLUDESRC\}/observe.ih
hellov.eh hellov.ih: $\{INCLUDESRC\}/point.h
hellov.eh hellov.ih: $\{INCLUDESRC\}/rect.h
hellov.eh hellov.ih: $\{INCLUDESRC\}/view.ih
hellov.eh hellov.ih: $\{SRCDIR\}include/class.h
}
\begindata{bp,537558784}
\enddata{bp,537558784}
\view{bpv,537558784,909,0,0}
Copyright 1992 Carnegie Mellon University and IBM.
All rights reserved.
\smaller{\smaller{$Disclaimer:
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose is hereby granted without fee,
provided that the above copyright notice appear in all copies and that
both that copyright notice, this permission notice, and the following
disclaimer appear in supporting documentation, and that the names of
IBM, Carnegie Mellon University, and other copyright holders, not be
used in advertising or publicity pertaining to distribution of the
software
without specific, written prior permission.
IBM, CARNEGIE MELLON UNIVERSITY, AND THE OTHER COPYRIGHT HOLDERS
DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT
SHALL IBM, CARNEGIE MELLON UNIVERSITY, OR ANY OTHER COPYRIGHT HOLDER
BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
OF THIS SOFTWARE.
$
}}\enddata{text,538947568}
Download