home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d9xx
/
d911
/
gadlayout.lha
/
GadLayout
/
GadLayout.Man
< prev
next >
Wrap
Text File
|
1993-10-03
|
22KB
|
455 lines
GadLayout version 36.22 release 1.6
The Dynamic Gadget Layout System
Copyright © 1992, 1993 by
Timothy J. Aston
All Rights Reserved
* IMPORTANT - Read This (PLEASE):
GadLayout is copyright, so you can't go ahead and just use it however you
want, there are some restrictions. GadLayout consists of the C source
files, all header files, and all documentation included. You may not
modify GadLayout in any way. GadLayout exists for you, the software
developer, to use it; however, certain conditions must be complied with
before you do:
1. Your documentation must clearly state that it is making use of the
GadLayout dynamic gadget layout system by Timothy Aston.
2. You must provide me with, free of charge, a copy of the software you use
GadLayout in, and any subsequent updates to it that use GadLayout, also
free of charge. This means that if the software you use it in is
shareware, I must be considered a full-registered user of the software.
Similarly for commercial software, you must provide me with a
complimentary copy. And in all cases, as long as your software continues
to use GadLayout, you must provide with all publically released updates.
See the end of this document to find out how to get the stuff to me.
I hope this isn't being too unreasonable, I basically just want to see
all the software that uses GadLayout.
3. If you modify the GadLayout source at all, you must send your
modifications to me. You may not under any circumstances use the
GadLayout sources to create any kind of runtime-linking module, such
as a standard Amiga shared-library.
4. You may not distribute modified GadLayout source, or include GadLayout
source in a distribution without permission from the author.
5. Any modified versions of GadLayout will fall under this same licensing
agreement.
* Requirements:
GadLayout is designed for use by programmers developing software for Release 2
and higher of the Amiga's operating system. Though it can make use of
locale.library, this is not required if you do not wish to make your gadgets
locale-sensitive. In fact, software using GadLayout only absolutely
requires V36 of the OS to run (unless you make use of some of the locale
features), however, it does REQUIRE V38 or greater of amiga.lib, because
it needs the locale symbols to compile.
* Introduction:
Anyone that tried to design an attractive GUI in the days before Release 2
has tremendous appreciation for the addition of gadtools.library. Nice
looking 3-D gadgets can be created and controlled with ease. Though this
was a major innovation, it is still lacking. Another nice addition in
Release 2 was much better support for user-definable fonts. The problem
is the GadTools does very little to help you adjust on the fly to different
font sizes, you must do all the calculations yourself. Anyone that has
tried to do this realizes that this is quite a tedious task indeed. What
most people end up doing (including Commodore themselves :( ) is hard-code
their programmes to use the Topaz 8 font. As an added complication, with
the advent of localization, programmes should now be able to adjust to adjust
to different languages.
GadLayout is an attempt to take care of these problems. It takes away the
job of having to calculate gadget sizes and positions relative to font
size and language being used. Under GadTools, size and position have to
be specified simply in absolute pixels. GadLayout is partly a frontend to
GadTools, allowing you to define size and height in much more complex ways
(though you can still specify absolute pixels, this will still be easier
than using straight GadTools, but it is not really taking advantage of the
power GadLayout offers). Gadgets can be automatically sized to fit text in
any font (including proportional), and can be aligned with other gadgets.
The actual technique is very simple, but gives you tremendous control over
the placement of your gadgets. GadLayout also expands on GadTools by
offering you some new gadget kinds.
This document is meant to be a tutorial in C for using GadLayout in your
programmes. Not every detail of GadLayout will be given here, for a full
reference, use the autodoc and includes file GadLayout.doc and gadlayout.h.
In fact, to properly learn about programming with GadLayout, you should be
consulting this document, the reference files and the examples concurrently.
* Before You Do Anything:
Though it maybe your software, you don't really have total freedom in the
design of its user interface. Commodore has a book called the User Interface
Style Guide that defines some standards in how programmes should appear and
opperate. So before you decide how your programme will look, you study this
book and make sure that it complies with the conventions Commodore has set
out.
* The Basics:
GadLayout requires that LocaleBase be declared. You do not need to open
locale.library if you don't want to use make your gadgets locale-sensitive,
but you will get a linker error if you don't declare it. In C, you would
use:
struct Library *LocaleBase = NULL;
Next comes the definitions of your gadgets. Each gadget you define as a
tag list. If you are not familiar with tag lists, please consult the
Amiga ROM Kernal Reference Manual: Libraries, it explains how to use them.
You should be able to get the jist from the examples as well. As with
any tag list, a GadLayout gadget tag list consists of a tag followed by
some piece of information. All the tags supported are defined in the C
header file gadlayout.h (sorry, no header files for other languages, C is all
I know). The only required tag is GL_GadgetKind, though you will always want
to use at least a few others. You only have to include tags for data that
has changed from the previous gadget, and tags can be given in any order
(NOTE: there are cases where this is not necessarily the case, see later
on). A basic gadget could be defined as follows:
struct TagItem mygad_layout_tags[] =
{
{ GL_GadgetKind, BUTTON_KIND },
{ GL_GadgetText, "Test Button" },
{ GL_Top, 4 },
{ GL_Left, 4 },
{ GL_Width, 140 },
{ GL_Height, 12 },
{ GL_Flags, PLACETEXT_IN },
{ TAG_DONE, NULL },
};
(The label before the comma is the tag, the expression to the left is that
tag data, and the two together are called a tag item. The examples given here
will use a variety of the available tags, but for a full listing with
explanations, you will need to consult the autodoc and header files.)
This example is very simple, and you really should not ever use something like
this in real life. The reason you shouldn't is because of the use of absolute
co-ordinates, this is not much better than using straight GadTools. If the
font we were using here was something large, even like Times 13, the text
would not fit in the gadget bounds and we'd get a mess. The idea is that
gadgets should adjust in size to different user fonts. Here's how you'd
really want to do it:
struct TagItem mygad_layout_tags[] =
{
{ GL_GadgetKind, BUTTON_KIND },
{ GL_LocaleText, MSG_GAD_TESTBUTTON },
{ GL_Top, 4 },
{ GL_Left, 4 },
{ GL_AutoWidth, 12 },
{ GL_AutoHeight, 4 },
{ GL_Flags, PLACETEXT_IN },
{ TAG_DONE, NULL }
};
We've made only three changes here. First of all, instead of hard-coding a
string, we'll be getting a string from our locale language catalog (how to
specify which catalog to use will be explained later on). Next problem is
fitting the text instead the gadget. For this, we use the GL_AutoHeight and
GL_AutoWidth tags. GL_AutoHeight will make the gadget's height adjust
automatically to whatever font the user is using (how to tell your gadgets
which font to use will also be explained later on). The data field in the
tag list (4 in our example) is a constant that gets added to the height
calculation, this is just so the text doesn't looked cramped inside the
gadget's border. GL_AutoWidth is similar, it looks at the gadget text and
makes the gadget wide enough to fit that text with the current font, and
also allows you to add a constant to that calculate to give a bit of a
border. Note that this is one of those cases where the order of the tags
DOES matter: if you want to use GL_AutoWidth you MUST use either GL_GadgetText
or GL_LocaleText beforehand; this is since GL_AutoWidth must know what the
text is in order to calculate its width.
You make tag lists such as the one above for every gadget you want to include
in your gadget list. After these are all defined, you need to group them
together in an array of LayoutGadget structures (see gadlayout.h). Each
element in the array is a gadget, it needs the gadget Intuition ID, and a
pointer to its GadLayout tag list. It also may need a pointer to its
GadTools tag list. GadTools tags are the tags that you would normally pass
to the GadTools function CreateGadgetA() when creating a GadTools function.
A very simple example might be:
struct mygad_gadtools_tags[] =
{
{ GT_Underscore, '_' },
{ TAG_DONE, NULL }
}
Lastly, each element in the array needs a spot where it will store the Gadget
structure pointer of the gadget once it gets created. This should be
initialized to NULL. All these go in an array, eg:
struct LayoutGadget mygadgets[] =
{
{ GAD_MYGAD1, mygad1_layout_tags, mygad1_gadtools_tags, NULL },
{ GAD_MYGAD2, mygad2_layout_tags, mygad2_gadtools_tags, NULL },
{ -1, NULL, NULL, NULL } /* Gadget ID of -1 marks the end */
}
All that's left is the actual creation and laying out of the gadgets. This is
done in one batch using a single call to the GadLayout function
LayoutGadgetsA() (or its var args stub, LayoutGadgets()). This routine takes
a pointer to your initialized gadget list pointer, the screen the gadgets are
going to made on, your LayoutGadget array, plus some tag lists for setting
various options. Here's how you might use it:
struct Gadget *glist;
WORD right_extreme, lower_extreme;
[...]
gi = LayoutGadgets(&glist, mygadgets, screen,
GL_RightExtreme, &right_extreme,
GL_LowerExtreme, &lower_extreme,
GL_DefTextAttr, screen->Font,
TAG_DONE);
The value returned is a pointer to a private structure. You must keep this
value in order to use the FreeLayoutGadgets() to properly free all resources.
If the gadgets couldn't be laid out for some reason (eg. no memory), then
the return value will be NULL.
This example makes use of some the tags that you can pass to LayoutGadgets().
The first two tags are used in conjunction to find out how far right and how
far down a window gadget imagery will be rendered. You use these values when
you open your window, so that you can have it sized to perfectly fit in all
your gadgets. The last tag, GL_DefTextAttr tells us which font to use for
all the gadgets defined (not that it is possible to use different fonts for
each gadget, but if they're all going to have the same font, this is a much
easier way of specifying it). Here we just grab the font that is being used
by whatever screen we are to open on. It is good practice to use the font
that the user has selected as the Screen font in his/her Font preferences
(you can get this by looking at wbscreen->Font) since you can very easily
make your gadgets adjust to any font using GadLayout.
If the call was successful, glist will be an initialized gadget list, ready to
be passed to OpenWindowTags(), AddGList(), etc. This is a GadTools gadget
list, so you must use gadtools.library functions such as GT_GetMsg() and
GT_RefreshWindow() to handle the processing of these gadgets.
You finish off with a called FreeLayoutGadgets() in order to release the
resources used by your gadgets. NOTE: Do NOT use the GadTools function
FreeGadgets() to free your gadgets, GadLayout uses some additional resources
that this function will not free.
* Fancy Stuff:
GadLayout provides you with tremendous power and flexability in defining your
gadgets. So far we've only just touched in this with the automatic sizing.
Another concept that GadLayout introduces is the idea of positioning and
sizing gadgets relative to others. Often times, you'll have gadgets generally
laid out in columns of some sort. Because gadget size will vary depending on
font size, you'll specify a gadget's top edge relative to the bottom edge of
the gadget immediately above it, using the GL_TopRel gadget. Usually you
will want all their widths to be the same, so you will use the GL_DupeWidth
tag to make the width of a gadget the same as another (you should duplicate
the width of the gadget with the longest string, so that others will be wide
enough). These are just a couple of examples, see the descriptions of the
available tags to see the extensive list of options you have available to
you in positioning gadgets.
You have to be a little careful when using tags like these that reference
other gadgets. It was stated before earlier that you need not specify tags
for items that haven't changed from the previous gadget, and that the order
of tags doesn't really matter. But you'll see that you have to be a little
more careful of this when using tags that reference other gadgets. To see
how, we'll have to look at how the gadgets are setup and laid-out by
GadLayout:
Each gadget in the array is processed sequentially, and all the values
calculated for it are preserved for the next gadget, so for a field that
doesn't change (eg. say you're making a column of gadgets, the left edge won't
change until you start a new column) you won't have to bother specifying it
again and again. But, once GadLayout hits a tag that refers to another
gadget, it must stop the processing of that gadget and process the referenced
gadget if it has not already been processed. Where problems can arise is if
this gadget attempts to reference back to the gadget that referenced it. That
gadget has only been partially processed, so not all fields in it will
necessarily be defined. And if the referencing tag needs to look at a field
that has not yet been calculated, you'll get a wrong result. Here's an
example:
struct TagItem button1_layout_tags[]
{
{ GL_GadgetKind, BUTTON_KIND },
{ GL_GadgetText, "A Button" },
{ GL_DupeWidth, GAD_BUTTON2 },
{ GL_AutoHeight, 4 },
{ GL_Top, 4 },
{ GL_Left, 4 },
{ GL_Flags, PLACETEXT_IN },
{ TAG_DONE, NULL }
};
struct TagItem button2_layout_tags[]
{
{ GL_GadgetKind, BUTTON_KIND },
{ GL_GadgetText, "Another Button" },
{ GL_AutoWidth, 12 },
{ GL_TopRel, GAD_BUTTTON1 },
{ GL_AddTop, 4 },
{ GL_Left, 4 },
{ GL_Flags, PLACETEXT_IN },
{ TAG_DONE, NULL }
};
This will not yield the correct result at all. When the GL_DupeWidth tag is
hit, processing will jump to the second gadget. Once it hits the GL_TopRel
gadget, it will look back at the first gadget, and see that it is already
being processed, so it won't try to process it now. It grab its top edge
and height fields to find its bottom edge so that the second gadget gets
placed relative to that. Problem is that the top edge and height for the
first gadget have not been calculated, so the second gadget will not get the
value you wanted for its top edge. In order to get what we want, we just
have to make sure that the top edge and height are already calculated before
the second gadget will reference them:
struct TagItem button1_layout_tags[]
{
{ GL_GadgetKind, BUTTON_KIND },
{ GL_GadgetText, "A Button" },
{ GL_Top, 4 },
{ GL_AutoHeight, 4 },
{ GL_DupeWidth, GAD_BUTTON2 },
{ GL_Left, 4 },
{ GL_Flags, PLACETEXT_IN },
{ TAG_DONE, NULL }
};
struct TagItem button2_layout_tags[]
{
{ GL_GadgetKind, BUTTON_KIND },
{ GL_GadgetText, "Another Button" },
{ GL_AutoWidth, 12 },
{ GL_TopRel, GAD_BUTTTON1 },
{ GL_AddTop, 4 },
{ GL_Left, 4 },
{ GL_Flags, PLACETEXT_IN },
{ TAG_DONE, NULL }
};
Its a little confusing, you just have to follow the order in which gadgets
will get processed, and you should be able to see why the first example is
wrong.
* GadLayout Gadget Kinds:
As mentioned in the introduction, GadLayout expands upon the gadget kinds
that GadTools supports. Currently, GadLayout adds three kinds: IMAGE_KIND,
DRAWER_KIND and FILE_KIND. IMAGE_KIND is very similar to the GadTools
BUTTON_KIND gadget, expect that instead of displaying text within, it will
show an Intuition Image structure. The DRAWER_KIND and FILE_KIND gadgets
are both very similar, and are essentially just special kinds of IMAGE_KIND
gadgets. You use them to allow the user to select a path of filename
respectively. When the user clicks a DRAWER_KIND gadget, you should bring
up an ASL file requester to allow the user to select a path (for example,
the directory where downloads are placed by a terminal programme). Likewise
for a FILE_KIND gadget so that the user may choose a filename (for example,
the name of a script to run). As a matter of style, accompany the DRAWER_KIND
and FILE_KIND gadgets with a string gadget to their immediate right so that
the user may type his/her selection instead of having to go through the file
requester.
These gadgets have tags specific to them, just like the GadTools gadgets do.
But instead of putting them in a seperate tag list like you do with the tags
for all GadTools gadget kinds, you include them with the GadLayout tags, eg:
struct TagItem drawergad_layout_tags[] =
{
{ GL_GadgetKind, IMAGE_KIND },
{ GL_GadgetText, "My _Image" },
{ GL_Top, 4 },
{ GL_Left, 4 },
{ GL_Width, 100 },
{ GL_Height, 60 },
{ GL_Flags, PLACETEXT_ABOVE },
{ GLIM_Image, NULL },
{ TAG_DONE, NULL }
};
[...]
drawergad_layout_tags[6].ti_Data = image;
The GLIM_Image tag is a tag specific for IMAGE_KIND gadgets. You use this to
point to the Image structure that you want displayed within the gadget. Note
here how we actually set this AFTER the tag list has been defined. This is
something you will need to do sometimes with GadLayout, since all information
is not necessarily known at initialization time (an excellent example of this
will be with a LISTVIEW_KIND gadget and the GTLV_Labels task, you will have
to first build the list, then you can set that pointer).
If you want to modify attributes of a GadLayout gadget kind, you must use the
GadLayout function GL_SetGadgetAttrsA() (or the var args stub
SetGadgetAttrs()) as opposed the the GadTools functions that you would use for
modifying a GadTools gadget kind.
* Acknowledgements:
I'd like to thank the following people, all of them were a great help in
getting GadLayout out the door:
- Mark Rickan (general input and support)
- Ralph Schmidt (for answers to various gadget related questions)
- Olaf Barthel (used some of the code from his Term 2.4)
- Pasi Ilola, for porting the assembler headers, and some suggestions.
- Commodore (for writing the Style Guide)
- U2, for the music (which I listen to most of the time while developing :)
* About the Author:
I (Tim Aston) am a university student, taking specialized honours computing
and information science at the University of Guelph. My hobbies include
computing, hockey (Montreal Canadiens all the way!), politics, etc. My
key interests in computing are personal computer application software and
operating systems, in particular how they relate to user interface design.
Some of you may know me as the author of TransAmiga BBS, and I've also been
around the FidoNet and IRC scene for a bit now, and may know me from there.
My current project is a text editor, and it was while writing this that I
realized how much a better system for laying out gadgets was needed. From its
initial conception to the first release, it has taken a little less than 2
months to produce GadLayout. I plan to continue to expand upon GadLayout
(particularly with new gadget kinds) for as long as there is a need and
sufficient demand.
If you're designing a programme with a GUI (whether it uses GadLayout or
not), feel free to get in contact with me for some suggestions and ideas
to improve upon it, I think I've got quite a knack for pointing out
deficiences in a GUI.
If you wish to contact me, any of the following means are fine:
IRC: Timmer @ #amiga
InterNet E-Mail: cs1087@snowhite.cis.uoguelph.ca
FidoNet: Tim Aston @ 1:247/192
FAX: (416)682-3501
Regular Mail: Tim Aston
128 Riverview Blvd.
St. Catharines, Ont.
L2T 3M2
Canada
Those are listed in the order in which I will generally be most swift in
replying. When you are releasing software that uses GadLayout, initially you
must send it through the mail to my home address, however you can use my
InterNet address to E-Mail me uuencoded updates. I may be open to other
means, just ask.
I thank you for you interest in GadLayout, and I'll be happy to listen to any
questions of comments you might have. I especially look forward to seeing
your programmes' high quality GUIs using GadLayout!
-Tim
¬