Intuition Gadgets — Classic Gadgets (Section 3.4)

This article synthesises Section 3.4 ("Gadgets") of Amiga C for Advanced Programmers by Bleek, Jennrich, Schulz (Abacus / Data Becker, ~1991). Section 3.4 is one of the longest in Chapter 3 (~50 pages, PDF pages 187–238) and covers the classic Intuition gadget model: struct Gadget, the gadget chain, the four built-in gadget kinds (boolean, string, integer, proportional), custom gadget rendering, and the high-level GadTools toolkit.

Editorial note: page numbers in this article refer to the PDF page index in the raw OCR source. Important: this article covers classic Intuition gadgets (pre-BOOPSI), not the modern BOOPSI gadget class system. For BOOPSI, see graphics/v39-aa-graphics-features.md and the autodocs for gadgetclass.


What a gadget is (page 187)

A gadget is a sub-region of a window that detects and reacts to user input. Compared to a window (which gets events for clicks anywhere on its surface), a gadget is a focused area with:

  • A specific kind (boolean button, text field, slider, etc.)
  • A specific region (top-left corner + width/height)
  • A specific IDCMP event it emits (IDCMP_GADGETUP, IDCMP_GADGETDOWN)
  • A specific way to render itself (Intuition-managed via flags, or application-managed via custom rendering)

Gadgets appear in two places:

  1. Title bar (system gadgets: close, size, depth, zoom, iconify)
  2. Window body (the application's gadgets: OK buttons, scroll bars, sliders, custom controls)

The book's editor uses gadgets heavily: OK buttons in requesters, scroll bars for the editing area, sliders for jump-to-line.


The classic Gadget structure (page 188)

struct Gadget {
    struct Gadget *NextGadget;       /* chain to the next gadget */
    WORD LeftEdge, TopEdge;          /* position relative to window origin */
    WORD Width, Height;              /* size */
    UWORD Flags;                     /* GADGH_*, GACT_* */
    UWORD Activation;                /* GADGIMMEDIATE | GADGFOLLOW | RELVERIFY */
    UWORD GadgetType;
    APTR GadgetRender;               /* Image or IntuiText */
    APTR SelectRender;               /* selected-state render */
    struct IBox *GadgetText;         /* optional text */
    LONG MutualExclude;              /* mutual-exclusion mask */
    UWORD SpecialInfo;               /* kind-specific data */
    UWORD GadgetID;                  /* application-defined ID */
    APTR UserData;                   /* application data */
};

For most applications, only a few fields are interesting:

  • Flags — visual/interaction flags
  • Activation — when/how the gadget responds
  • GadgetType — which built-in kind
  • SelectRender — what to draw when active
  • GadgetID — your tag for finding the gadget after a GadgetUp event

The book walks through each field in detail (page 188-200).


The four built-in gadget kinds

The book's section 3.4 is organised around these kinds:

Boolean gadgets (page ~200)

A simple on/off button:

struct NewGadget ng_bool = {
    40, 60, 80, 14,           /* x, y, w, h */
    "OK",                     /* label */
    &myButtonImage,           /* unselected image */
    &myButtonSelectImage,     /* selected image */
    0,                        /* placement */
    1,                        /* gadget ID */
    NULL                      /* userdata */
};
struct Gadget *ok_g = (struct Gadget *)CreateGadgetA(
    GADGETBUTTON_KIND,        /* kind */
    &ng_bool,
    NULL                       /* tag list */
);

CreateGadgetA() (added in OS 2.0) is the modern way to create classic gadgets from a NewGadget template.

IDCMP_GADGETUP arrives when the user releases the mouse button on the gadget.

String gadgets (page ~210)

A text input field:

struct Gadget *str_g = CreateGadgetA(
    STRING_KIND,
    &ng_string,
    NULL
);
AddGadget(window, str_g);
RefreshGadgets(str_g, window);

String gadgets have a buffer (typically 64 bytes), a maximum-length, and a workbench-like cursor. IDCMP_GADGETUP arrives when the user presses Enter.

Integer gadgets (page ~220)

A numeric input field with up/down arrows:

struct Gadget *int_g = CreateGadgetA(
    INTEGER_KIND,
    &ng_integer,
    NULL
);

IDCMP_GADGETUP arrives when the user clicks the arrows or presses Enter.

Proportional gadgets (page ~230)

A slider/scrubber:

struct Gadget *prop_g = CreateGadgetA(
    PROPGADGET_KIND,
    &ng_prop,
    NULL
);

The prop gadget reports its body and pot position via the standard gadget fields. IDCMP_GADGETUP arrives when the user releases the mouse.


Activation and flags (page ~205)

Activation

Flag Effect
GACT_IMMEDIATE Fire IDCMP_GADGETDOWN on press, IDCMP_GADGETUP on release (button-like)
GACT_RELVERIFY Fire IDCMP_GADGETUP only if the user releases on the gadget
GACT_FOLLOW Continuously fire IDCMP_GADGETUP while the user holds (slider-like)

RELVERIFY is the safe default for most buttons: prevents accidentally clicking through a dialog if the user drags out.

Flags

Flag Effect
GADGH_COMP Complement (XOR) render when selected
GADGH_NONE No render selected appearance
GADGH_IMAGE Use the SelectRender image when selected
GADGH_TEXT Use the SelectRender IntuiText when selected
GADGH_BOXES Draw a box outline when selected
GADGH_RBUTTON Render like a Workbench radio button
GADGH_CBOX Render like a checkbox
GFLG_SELECTED The gadget starts in the selected state
GFLG_TABCYCLE Tab key moves focus to next gadget
GFLG_TABSTOP Gadget is a tab-stop

MutualExclude (page ~207)

The MutualExclude field is a bitmask of gadget IDs. If two gadgets share a bit, activating one deactivates the other. Classic pattern for radio-button groups:

ng_radio1.MutualExclude = (1 << GADGET_ID_RADIO2) | (1 << GADGET_ID_RADIO3);
ng_radio2.MutualExclude = (1 << GADGET_ID_RADIO1) | (1 << GADGET_ID_RADIO3);
ng_radio3.MutualExclude = (1 << GADGET_ID_RADIO1) | (1 << GADGET_ID_RADIO2);

Gadget IDs 1-15 form the mutual-exclusion bits (a 16-bit mask).


Adding gadgets to a window (page ~190)

Classic gadgets must be added to the window's gadget chain:

AddGadget(window, &ng_bool.Gadget, 0);  /* legacy form, OS 1.x */
/* or: */
AddGadget(window, ok_g, 0);             /* modern form, OS 2.0+ */
RefreshGadgets(ok_g, window);            /* redraw */

RefreshGadgets() causes intuition.library to redraw the gadget using its current image/flag settings.

To remove:

RemoveGadget(window, ok_g);

Custom gadgets (page ~240)

When none of the four built-in kinds fit, write your own:

static struct Image my_button_image = {
    0, 0,
    80, 14,
    2,                              /* depth (2 bitplanes = 4 colours) */
    &my_button_data,                /* pixel data */
    4, 0,                           /* pick me first colour */
    NULL                            /* next image */
};

struct Gadget *my_gadget = (struct Gadget *)CreateGadgetA(
    CUSTOM_KIND,
    &ng_my,
    NULL
);

Custom gadgets don't have a built-in render. The application must:

  1. Draw the gadget in its window's refresh event
  2. Provide a hit-test region (via the image or its bounding box)
  3. Handle the IDCMP_GADGETUP / DOWN events it emits

The book covers several custom-gadget examples for the editor: the scroll-bar, the cursor-position bar, the line-jumper.


The high-level GadTools toolkit (page ~245)

The book briefly introduces GadTools, which provides higher-level gadget kinds than the four built-ins:

  • ListView
  • Scroller (replaces manual proportional-gadget logic)
  • TextDisplay
  • Cycle (radio buttons as a single gadget)
  • Integer, String, Boolean (with cleaner creation)
  • CheckBox, MutuallyExclusive
  • Slider (numeric slider with continuous update)
  • GetFile, GetFont, GetScreen, GetColor (file/dialog gadget host)

The book only briefly introduces GadTools because it came with OS 2.0; the editor uses classic gadgets throughout Chapter 3. The full GadTools coverage is in gadtools/gadtools-library-reference.md and library-reference/gadtools-library.md (21 functions).


What's NOT in section 3.4

  • BOOPSI gadget classes (the modern OO-style gadget system). These came later with OS 3.0 and replaced classic gadgets for new code. See the autodocs for gadgetclass in the OS 3.5+ NDK.
  • ReAction (the BOOPSI library that ships with OS 3.5+). See gadtools/reaction-gui-toolkit.md.
  • MUI (third-party gadget toolkit by Stefan Stuntz). See gui/mui-toolkit.md.
  • Layout (GadTools' automatic positioning). The book pre-dates Layout; manually calculating gadget positions is what the editor examples show.

Modern migration notes

If you're writing new code today:

Use this Instead of this Why
OpenWindowTagList() OpenWindow() with NewWindow Modern API
Layout for positioning Manual pixel positions Easier to maintain
BOOPSI gadget classes Classic gadgets OO-style, customisable
GadTools for built-in kinds Classic kinds Saner API
WindowUserData() Global state Window-attached state
IExec->Wait() WaitPort() Multi-source waiting

But the fundamentals the book describes (Activation, MutualExclude, GADGH flags, refresh handling) all still apply.


Sources

The classic gadget model covered in the book is still applicable for compatibility code; new development should use BOOPSI or ReAction instead.