/*  "ram:but.c"  10/15/88 */

/*-------------------------------------------------------------------------+
 | This is an example of how 'radio buttons' could be implemented using    |
 | gadgets. I use the GadgetID and UserData fields of the gadget structure |
 | to keep track of each set of radio buttons. When the user clicks on a   |
 | radio button a varaible is set and an optional function is called with  |
 | the variable as an argument. In order for this to work you must call    |
 | HandleGadgets() when the appropriate gadget related message comes across|
 | the IDCMP. There is a function called SetRadioButtons() sets the initial|
 | state of the buttons. If you modify the radio button variable for a set |
 | of buttons then you will have to call SetRadioButtons() to display the  |
 | proper state of the radio buttons. To terminate the program press a key.|
 | Look below for more comments.                                           |
 |                                                                         |
 |     This program is in the public domain, and may not be sold.          |
 |                                                                         |
 |          Written by Robert W. Albrecht                                  |
 |          1457 Zion Way                                                  |
 |          Ventura CA 93003                                               |
 +-------------------------------------------------------------------------*/


/* WARNING: This program contains bit maps in static data and must be
 * linked with the +Cdb option (Aztec) or ATOM'd (Lettuce) to work with
 * expanded memory. */


#include <intuition/intuition.h>
#include <exec/types.h>

#define INTUITION_REV 33L
#define GRAPHICS_REV 33L
#define DISKFONT_REV 33L

#define ZILCH 0

extern struct Library *OpenLibrary();
extern struct Window *OpenWindow();
extern struct Screen *OpenScreen();
extern struct TextFont *OpenFont();
extern struct Message *GetMsg();
extern struct ViewPort *ViewPortAddress();
extern long Wait();

/*** *** *** *** *** *** *** DATA *** *** *** *** *** *** *** ***/

/* GLOBAL LIBRARY BASE POINTERS */
struct IntuitionBase *IntuitionBase = 0L;
struct GfxBase *GfxBase = 0L;
struct DiskfontBase *DiskfontBase = 0L;

/* Resources */
struct Window *window;
struct Screen *screen;
struct TextFont *font;


UWORD _colors[16] =
   {
   0xe,
   0x0,
   0xeee,
   0xddd,
   0xccc,
   0xbbb,
   0xaaa,
   0x999,
   0x97,
   0x888,
   0xaaa,
   0xfca,
   0xfe0,
   0xccc,
   0x888,
   0x444,
   };

void test_func(i)
short i;
{
}

/* bit maps in butimg.c */
extern struct Image button_out, button_pressed;

#define RADIO_BUTTON 0x8000
#define RADIO_ACTIVATE (TOGGLESELECT | GADGIMMEDIATE)
#define DUAL_IMAGE (GADGHIMAGE | GADGIMAGE)

/* There must be one of these structures for each set of radio buttons.
 * The 'value' field must point to a separate variable for each set of
 * radio buttons. When a button is pressed the 'value' field will be
 * changed to the GadgetID & ~RADIO_BUTTON. Also if the 'func' field is
 * non-NULL the attached function is called with '*value' as the argument.
 */

typedef struct
{
void (*func)();       /* Function to call */
UWORD *value;         /* Value to change */
} RadioInfo;

UWORD variable = 5;  /* Set the initial state to what you want. */

RadioInfo rad_info =
{
test_func,
&variable,
};

/* It is important that the gadget ID be 'ord' with RADIO_BUTTON for the
 * functions to know this is a radio button. Also be sure you set the
 * TOGGLESELECT activation flag. The buttons only make sense if they have
 * two visual states, use GadgetRender and SelectRender. */

struct Gadget buttons[] =
{

   { /* 0 */
   &buttons[1],
   20,20,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 0,
   (APTR)&rad_info,
   },

   { /* 1 */
   &buttons[2],
   50,20,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE ,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 1,
   (APTR)&rad_info,
   },

   { /* 2 */
   &buttons[3],
   80,20,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 2,
   (APTR)&rad_info,
   },

   { /* 3 */
   &buttons[4],
   110,20,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 3,
   (APTR)&rad_info,
   },
   {  /* 4 */
   &buttons[5],
   140,20,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 4,
   (APTR)&rad_info,
   },
   {  /* 5 */
   &buttons[6],
   20,40,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 5,
   (APTR)&rad_info,
   },
   {  /* 6 */
   &buttons[7],
   50,40,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 6,
   (APTR)&rad_info,
   },
   {  /* 7 */
   &buttons[8],
   80,40,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 7,
   (APTR)&rad_info,
   },
   {  /* 8 */
   &buttons[9],
   110,40,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 8,
   (APTR)&rad_info,
   },
   {  /* 9 */
   &buttons[10],
   140,40,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 9,
   (APTR)&rad_info,
   },
   {  /* 10 */
   &buttons[11],
   20,60,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 10,
   (APTR)&rad_info,
   },
   {  /* 11 */
   &buttons[12],
   50,60,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 11,
   (APTR)&rad_info,
   },
   {  /* 12 */
   &buttons[13],
   80,60,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 12,
   (APTR)&rad_info,
   },
   {  /* 13 */
   &buttons[14],
   110,60,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 13,
   (APTR)&rad_info,
   },
   {  /* 14 */
   &buttons[15],
   140,60,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 14,
   (APTR)&rad_info,
   },
   { /* 15 */
   &buttons[16],
   20,80,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 15,
   (APTR)&rad_info,
   },

   { /* 16 */
   &buttons[17],
   50,80,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 16,
   (APTR)&rad_info,
   },

   { /* 17 */
   &buttons[18],
   80,80,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 17,
   (APTR)&rad_info,
   },

   { /* 18 */
   &buttons[19],
   110,80,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 18,
   (APTR)&rad_info,
   },
   {  /* 19 */
   &buttons[20],
   140,80,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 19,
   (APTR)&rad_info,
   },
   {  /* 20 */
   &buttons[21],
   20,100,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 20,
   (APTR)&rad_info,
   },
   {  /* 21 */
   &buttons[22],
   50,100,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 21,
   (APTR)&rad_info,
   },
   {  /* 22 */
   &buttons[23],
   80,100,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 22,
   (APTR)&rad_info,
   },
   {  /* 23 */
   &buttons[24],
   110,100,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 23,
   (APTR)&rad_info,
   },
   {   /* 24 */
   NULL,
   140,100,22,16,
   DUAL_IMAGE,
   RADIO_ACTIVATE,
   BOOLGADGET,
   (APTR)&button_out,
   (APTR)&button_pressed,
   NULL,
   0L,
   NULL,
   RADIO_BUTTON | 24,
   (APTR)&rad_info,
   },
};


/* TextAttr Declaration */
static struct TextAttr _ta =
{
(STRPTR) "topaz.font",
8,
FS_NORMAL,
ZILCH | FPF_ROMFONT,
};

/* NewScreen DECLARATION */
static struct NewScreen _ns =
{
0, 0, 640, 400, 4,
(UBYTE) 1,
(UBYTE) 0,
ZILCH | HIRES | LACE,
CUSTOMSCREEN,
&_ta,
(UBYTE *) "Button Test",
0L,
0L,
};


/* NewWindow DECLARATIONS */
static struct NewWindow _nw =
{
0, 0, 640, 400,
(UBYTE) 0,
(UBYTE) 1,
ZILCH | GADGETDOWN | GADGETUP | RAWKEY,
ZILCH | BACKDROP | BORDERLESS | ACTIVATE
 | SMART_REFRESH,
buttons,
0L,
0L,
0L,
0L,
2, 2,
640, 400,
CUSTOMSCREEN,
},
;


/*** *** *** *** *** *** _initialize() *** *** *** *** *** *** *** ***/

struct Window *_initialize()
{
extern void _goodbye();
struct ViewPort *vp;

/* OPEN THE LIBRARIES */
IntuitionBase =
(struct IntuitionBase*)OpenLibrary("intuition.library",(long) INTUITION_REV);
if( !IntuitionBase ) goto abort;

GfxBase =
(struct GfxBase*)OpenLibrary("graphics.library", (long) GRAPHICS_REV);
if( !GfxBase ) goto abort;

/* OPEN THE FONT */
if( !( font = OpenFont( &_ta ) ) )
   goto abort;

/* OPEN THE SCREEN */
if( !(screen = OpenScreen( &_ns ) ) )
   goto abort;

/* OPEN THE WINDOW */
_nw.Screen = screen;
if( !( window = OpenWindow( &_nw ) ) )
   goto abort;

SetFont(window->RPort,font);

/* LOAD COLORS INTO VIEWPORT */
vp = ViewPortAddress(window);
LoadRGB4(vp,_colors,16L);

return(window);

abort:
_goodbye();
return(0L);
}


/*** *** *** *** *** *** _goodbye *** *** *** *** *** *** *** *** ***/

void _goodbye()
{

if( font )
   CloseFont(font);
if( window )
   CloseWindow(window);
if( screen )
   CloseScreen(screen);

if( IntuitionBase )
   CloseLibrary(IntuitionBase);
if( GfxBase )
   CloseLibrary(GfxBase);
if( DiskfontBase )
      CloseLibrary( DiskfontBase);
}


main()
{
extern void HandleGadgets();
extern void SetRadioButtons();

struct Window *w;
struct IntuiMessage I, *msg;

if( w = _initialize() )
   {

   SetRadioButtons(w);

   for(;;)
      {
      Wait( 1L<<w->UserPort->mp_SigBit );
      while( msg = (struct IntuiMessage *) GetMsg(w->UserPort) )
         {
         I = *msg;
         ReplyMsg(msg);

         if( I.Class == RAWKEY )
            goto stop;
         else if( I.Class == GADGETDOWN )
         /* You should call this function when you get gadget related
          * messages. It will take care of the 'radio buttons' for you. */
            HandleGadgets(&I);
         }
      }

   stop:
   _goodbye();
   }
}

/* Takes care of radio button IO */

void HandleGadgets(i)
struct IntuiMessage *i;
{
register struct Gadget *this_one = (struct Gadget *)i->IAddress;

/* Test to see if this is a radio button */

if( this_one->GadgetID & RADIO_BUTTON )
   {
   register struct Gadget *g = i->IDCMPWindow->FirstGadget;
   register RadioInfo *info = (RadioInfo *)this_one->UserData;

   /* find old button and turn it off */
   for(; g; g = g->NextGadget)
      if( g->GadgetID & RADIO_BUTTON )
         if( *info->value == (g->GadgetID & ~RADIO_BUTTON) &&
             g->UserData == ((APTR)info) )
               break;

   if( !g ) return; /* Abortion */


   /* Modify the gadget images */
   if( g != this_one )
      {
      g->Flags &= ~SELECTED;
      RefreshGList(g,i->IDCMPWindow,0L,1);
      }
   else if( !(g->Flags & SELECTED) )
      {
      g->Flags |= SELECTED;
      RefreshGList(g,i->IDCMPWindow,0L,1);
      }

   /* Set the value of the radio button varaible */
   *info->value = (this_one->GadgetID & ~RADIO_BUTTON);

   /* Call user function if there is one */
   if( info->func )
      (*info->func)(*info->value);
   }
}

/* Call this function after you change the radio button variable or
 * to initialize the visual state. */

void SetRadioButtons(w)
struct Window *w;
{
register struct Gadget *g = w->FirstGadget;

for(; g; g = g->NextGadget )
   if( g->GadgetID & RADIO_BUTTON )
      {
      if( (*((RadioInfo *)g->UserData)->value) ==
          (g->GadgetID & ~RADIO_BUTTON) )
         g->Flags |= SELECTED;
      else
         g->Flags &= ~SELECTED;
      RefreshGList(g,w,0L,1);
      }
}

/* Have fun girls and boys */
