GadTools V47 Additions¶
gadtools.library 47 (AmigaOS 3.2) is the first functional update of GadTools since V40. It adds a font-relative grid layout (NG_GRIDLAYOUT with the new functions SetDesignFontA() and ScaleGadgetRectA()), context frames with headlines for DrawBevelBoxA(), two read-only listview attributes, a scaled MX spacing, square scroller arrows, and support for Intuition's new menu glyphs and mouse-wheel scrolling. Programs that use none of it behave as before; programs that use it should open gadtools.library with version 47 or check the version first. On older versions the new tags are simply ignored ("New to V47 GadTools. Ignored by older versions").
For the classic GadTools programming model (CreateContext, CreateGadgetA, GT_GetIMsg) see GadTools Library Reference.
New functions¶
| Function | LVO | Registers | Purpose |
|---|---|---|---|
LONG SetDesignFontA(APTR vi, struct TextAttr *tattr, CONST struct TagItem *tags) |
−138 | A0/A1/A2 | define the font the grid layout is based on |
LONG ScaleGadgetRectA(struct NewGadget *ng, CONST struct TagItem *tags) |
−144 | A0/A1 | scale one NewGadget rectangle by the grid |
Both have varargs stubs (SetDesignFont(), ScaleGadgetRect()). The four slots that follow (−150 … −168) are private/reserved; GT_GetGadgetAttrsA() stays at −174.
Grid layout: NG_GRIDLAYOUT¶
#define NG_GRIDLAYOUT 0x0080 /* scale positions along the design font
set by SetDesignFont() */
When NG_GRIDLAYOUT is set in ng_Flags, CreateGadgetA() does not take ng_LeftEdge, ng_TopEdge, ng_Width and ng_Height as pixels. Each of these WORDs is a fixed-point grid value:
| Bits | Meaning |
|---|---|
| 15–6 | whole font cells |
| 5–4 | quarter cells (fractional part) |
| 3–0 | signed pixel offset: 0 = none, 1…7 = +1…+7, 15 = −1 (two's complement nibble) |
In other words, the upper 12 bits count quarters of the font width (horizontal values) or font height (vertical values), and the low 4 bits add a small pixel correction. A whole cell is n << 6; a quarter cell is n << 4. Without SetDesignFontA() the grid is based on an 8×8 cell (topaz 8).
The autodoc gives rules of thumb for sizes:
| Gadget | Height | Notes |
|---|---|---|
| Buttons | 7 << 4 |
1.75 cells |
| Checkboxes | 6 << 4 high, 13 << 4 wide |
1.5 cells high |
| Horizontal sliders | 5 << 4 |
1.25 cells |
The grid origin is the window's inner top-left corner: GTVI_LeftBorder defaults to screen->WBorLeft, and GTVI_TopBorder to screen->WBorTop + screen->Font->ta_YSize + 1 (a normal window with a drag bar). Set both to 0 for borderless or WFLG_GIMMEZEROZERO windows.
A handy pair of macros:
#define GCELL(n) ((WORD)((n) << 6)) /* whole cells */
#define GQUART(q) ((WORD)((q) << 4)) /* quarter cells */
#define GOFFS(v,pix) ((WORD)((v) | ((pix) & 15)))/* + pixel offset */
SetDesignFontA¶
LONG SetDesignFontA(APTR vi, struct TextAttr *tattr, CONST struct TagItem *tags);
Sets the font that the grid layout of this VisualInfo is based on. vi must not be NULL. The TextAttr is not referenced after the call. Returns 0 on failure.
| Tag | Value | Meaning |
|---|---|---|
GTVI_LeftBorder 3.2+ |
GT_TagBase+96 |
left offset of the design grid (default: current VisualInfo setting) |
GTVI_TopBorder 3.2+ |
GT_TagBase+97 |
top offset of the design grid |
GTVI_MinFontWidth 3.2+ |
GT_TagBase+100 |
minimum cell width in pixels; used if the font is narrower (default 0) |
GTVI_MinFontHeight 3.2+ |
GT_TagBase+101 |
minimum cell height in pixels (default 0) |
GTVI_LeftBorder and GTVI_TopBorder are also accepted by GetVisualInfoA(). GT_TagBase is TAG_USER + 0x80000.
ScaleGadgetRectA¶
LONG ScaleGadgetRectA(struct NewGadget *ng, CONST struct TagItem *tags);
If NG_GRIDLAYOUT is set, converts the four grid values in ng to pixels using the design font, then clears NG_GRIDLAYOUT. It returns non-zero if it scaled, 0 if ng was left alone. CreateGadgetA() uses the same routine internally; the public entry point exists so you can pre-compute sizes, for example the window size. The design font "should best be identical" to ng_TextAttr.
| Tag | Value | Meaning |
|---|---|---|
GTVI_AlignRight 3.2+ |
GT_TagBase+98 |
snap the right edge to a grid position instead of scaling the width |
GTVI_AlignBottom 3.2+ |
GT_TagBase+99 |
snap the bottom edge to a grid position instead of scaling the height |
The autodoc example computes one cell at position 2,3:
ng.ng_LeftEdge = 2 << 6;
ng.ng_TopEdge = 3 << 6;
ng.ng_Width = 1 << 6;
ng.ng_Height = 1 << 6;
ng.ng_Flags = NG_GRIDLAYOUT;
ScaleGadgetRect(&ng, TAG_DONE);
Gotcha: junk in ng_Flags¶
Release 47.2 notes: "Some programs leave junk in ng_Flags and then trigger erroneously the font scaling algorithm. The scaler now attempts to detect such junk and disables itself upon its detection." Always initialise ng_Flags fully. Old code that never cleared it can get its gadgets silently scaled, or a new program can get its grid layout disabled.
Example: a font-sensitive window¶
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <libraries/gadtools.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/gadtools.h>
#define GCELL(n) ((WORD)((n) << 6))
#define GQUART(q) ((WORD)((q) << 4))
struct Library *GadToolsBase;
struct IntuitionBase *IntuitionBase;
int main(void)
{
struct Screen *scr;
APTR vi;
struct Gadget *glist = NULL, *gad;
struct NewGadget ng;
struct Window *win = NULL;
WORD innerw, innerh;
IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 47);
GadToolsBase = OpenLibrary("gadtools.library", 47);
if (!IntuitionBase || !GadToolsBase) goto out;
if (!(scr = LockPubScreen(NULL))) goto out;
if ((vi = GetVisualInfo(scr, TAG_DONE)))
{
/* grid is based on the screen font */
SetDesignFont(vi, scr->Font, TAG_DONE);
/* pre-compute the inner size of a 24 x 5 cell design area */
ng.ng_LeftEdge = 0; ng.ng_TopEdge = 0;
ng.ng_Width = GCELL(24); ng.ng_Height = GCELL(5);
ng.ng_TextAttr = scr->Font; ng.ng_VisualInfo = vi;
ng.ng_GadgetText = NULL; ng.ng_GadgetID = 0;
ng.ng_UserData = NULL; ng.ng_Flags = NG_GRIDLAYOUT;
ScaleGadgetRect(&ng, TAG_DONE);
innerw = ng.ng_Width;
innerh = ng.ng_Height;
gad = CreateContext(&glist);
/* string gadget: x=8 cells, y=1 cell, 15 cells wide, 1.75 high */
ng.ng_LeftEdge = GCELL(8); ng.ng_TopEdge = GCELL(1);
ng.ng_Width = GCELL(15); ng.ng_Height = GQUART(7);
ng.ng_GadgetText = "_Name"; ng.ng_GadgetID = 1;
ng.ng_Flags = NG_GRIDLAYOUT | PLACETEXT_LEFT;
gad = CreateGadget(STRING_KIND, gad, &ng,
GT_Underscore, '_', TAG_DONE);
/* OK button: x=1 cell, y=3 cells */
ng.ng_LeftEdge = GCELL(1); ng.ng_TopEdge = GCELL(3);
ng.ng_Width = GCELL(8); ng.ng_Height = GQUART(7);
ng.ng_GadgetText = "_OK"; ng.ng_GadgetID = 2;
ng.ng_Flags = NG_GRIDLAYOUT | PLACETEXT_IN;
gad = CreateGadget(BUTTON_KIND, gad, &ng,
GT_Underscore, '_', TAG_DONE);
if (gad)
win = OpenWindowTags(NULL,
WA_PubScreen, scr,
WA_Title, "Grid layout",
WA_InnerWidth, innerw,
WA_InnerHeight, innerh,
WA_DragBar, TRUE, WA_DepthGadget, TRUE,
WA_CloseGadget, TRUE, WA_Activate, TRUE,
WA_Gadgets, glist,
WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_REFRESHWINDOW |
STRINGIDCMP | BUTTONIDCMP,
TAG_DONE);
if (win)
{
BOOL done = FALSE;
GT_RefreshWindow(win, NULL);
while (!done)
{
struct IntuiMessage *im;
WaitPort(win->UserPort);
while ((im = GT_GetIMsg(win->UserPort)))
{
if (im->Class == IDCMP_CLOSEWINDOW) done = TRUE;
if (im->Class == IDCMP_REFRESHWINDOW)
{
GT_BeginRefresh(win);
GT_EndRefresh(win, TRUE);
}
GT_ReplyIMsg(im);
}
}
CloseWindow(win);
}
FreeGadgets(glist);
FreeVisualInfo(vi);
}
UnlockPubScreen(NULL, scr);
out:
if (GadToolsBase) CloseLibrary(GadToolsBase);
if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
return 0;
}
The same source then lays out correctly with topaz 8, a 13-point screen font or anything in between. With a fixed pixel layout it would overlap or leave gaps.
GTMX_ScaledSpacing¶
GTMX_ScaledSpacing (GT_TagBase+102, UWORD) is GTMX_Spacing given in grid units, so radio buttons keep their spacing when the GUI scales. It overrides GTMX_Spacing when NG_GRIDLAYOUT is set and is ignored otherwise.
Bevel boxes: display and context frames¶
DrawBevelBoxA() gains two frame types and four tags:
| Frame type | Value | Look |
|---|---|---|
BBFT_BUTTON 3.1+ |
1 | button box |
BBFT_RIDGE 3.1+ |
2 | string-gadget ridge |
BBFT_ICONDROPBOX 3.1+ |
3 | icon drop box |
BBFT_DISPLAY 3.2+ |
6 | recessed display box (V47) |
BBFT_CTXTFRAME 3.2+ |
7 | context frame with headline (V47) |
| Tag | Value | Type | Meaning |
|---|---|---|---|
GTBB_Scale 3.2+ |
GT_TagBase+92 |
BOOL | treat the coordinates as grid values (see above) |
GTBB_Headline 3.2+ |
GT_TagBase+93 |
UBYTE * |
headline centred on top of a BBFT_CTXTFRAME box |
GTBB_HeadlinePen 3.2+ |
GT_TagBase+94 |
UBYTE | pen for the headline; default HIGHLIGHTTEXTPEN |
GTBB_HeadlineFont 3.2+ |
GT_TagBase+95 |
struct TextAttr * |
headline font; default is the RastPort's font |
DrawBevelBox(win->RPort, GCELL(1), GCELL(1), GCELL(22), GCELL(4),
GT_VisualInfo, vi,
GTBB_Scale, TRUE,
GTBB_FrameType, BBFT_CTXTFRAME,
GTBB_Headline, "Options",
TAG_DONE);
Notes:
BBFT_CTXTFRAME"requires intuition V47 to render anything". It maps toFRAME_CONTEXTin frameiclass, and both constants were renumbered before release to avoid a clash.- Headlines need gadtools 47.13 or later. From that version
DrawBevelBoxA()passesIA_Label/IA_LabelPento frameiclass instead ofIA_Data/IA_FGPen(see Intuition V47 BOOPSI and Input Extensions). - A bevel box is rendering, not a gadget. Redraw it on
IDCMP_REFRESHWINDOWlike any other rendering.
Listview: GTLV_Total and GTLV_Visible¶
Two read-only attributes for GT_GetGadgetAttrsA() on LISTVIEW_KIND (gadtools 47.13):
| Tag | Value | Type | Meaning |
|---|---|---|---|
GTLV_Total 3.2+ |
GT_TagBase+92 |
UWORD | total number of items |
GTLV_Visible 3.2+ |
GT_TagBase+93 |
UWORD | number of visible items |
They have the same numeric values as GTBB_Scale/GTBB_Headline. The header explains that "no conflicts are possible due to the wholly different usage contexts". Together with GTLV_Top they let you build page-up/page-down keys and your own scrolling:
ULONG top, vis, total;
if (GT_GetGadgetAttrs(lv, win, NULL,
GTLV_Top, &top, GTLV_Visible, &vis,
GTLV_Total, &total, TAG_DONE) == 3)
{
LONG newtop = (LONG)top + (LONG)vis; /* page down */
if (newtop > (LONG)total - (LONG)vis) newtop = (LONG)total - (LONG)vis;
if (newtop < 0) newtop = 0;
GT_SetGadgetAttrs(lv, win, NULL, GTLV_Top, newtop, TAG_DONE);
}
GT_GetGadgetAttrsA() returns the number of attributes it filled in, so compare the result with the number of tags you asked for before using the values.
Scrollers, sliders and the mouse wheel¶
GTSC_Arrowsaccepts −1 (47.12) for "square arrow buttons". The size is corrected for screen aspect ratio and capped at a quarter of the scroller length. Listview scrollers always use square arrows now, instead of arrows as tall as one item.- Scroller and slider knobs get a 3D embossed look and a darker container with intuition.library 47.44 or later (47.11), and are drawn selected while dragged (47.12).
- GadTools gadgets take part in Intuition's OS-level scroll-wheel support (47.6). See Intuition V47 BOOPSI and Input Extensions for
IDCMP_EXTENDEDMOUSE.
Menus¶
- Items with a sub-menu no longer get a "»" (ASCII 187) appended. GadTools sets the Intuition
SUBMENUflag and Intuition draws itsMENUSUBsysiclass image (gadtools 47.8; the image was added in intuition 47.28). - Menu layout takes the
MENUMXandMENUSUBglyphs into account, and items are never shorter than the tallest standard menu glyph. - The Shift symbol for
MIF_SHIFTCOMMSEQitems is laid out correctly (47.5, 47.10), and since 47.16 the flag also applies to command strings. LayoutMenusA()no longer crashes on BOOPSI images used as menu labels (45.1).
Other fixes worth knowing¶
| Version | Change |
|---|---|
| 47.4 | GTMX_Active beyond the number of choices activates the last one instead of crashing |
| 47.7 | STRING_KIND with GTST_String longer than GTST_MaxChars is now truncated properly |
| 47.14 | a slider prototype change was reverted because it broke programs that peek the gadget structure |
| 47.15 | the autodoc now documents GTSL_DispFunc: LONG (*function)(struct Gadget *g, LONG level), both arguments passed on the stack as 32-bit values; level is in −32768…32767 |
See Also¶
- GadTools Library Reference
- gadtools.library function reference
- Intuition V47 BOOPSI and Input Extensions
- ReAction GUI Toolkit
- AmigaOS 3.2 — What Changed for Developers
Sources: NDK 3.2 R4 Include_H/libraries/gadtools.h, SFD/gadtools_lib.sfd, FD/gadtools_lib.fd, Autodocs/gadtools.doc, ReleaseNotes/gadtools-RelNotes, ReleaseNotes/intuition-RelNotes Updated: 2026-11-13