Copyright (c) 2012-2016 Hyperion Entertainment and contributors.

Programming AmigaOS 4: Intuition - The User Interface

From AmigaOS Documentation Wiki
Jump to: navigation, search

This article was adapted from Amiga Future magazine's series on developing for AmigaOS....

After having worked "under the hood" in the two last issues, we'll be working with the interface from now on. The first point to understand is Intuition as an interface to the user. We'll try to show you what kind of innovations there are especially in the interface.

This issue's topic is massive, as Intuition is practically in charge of the complete 'Look & Feel', so there is quite a lot to explain as well.

First of all, I have to remind you that there are no custom chips any longer on the new computers and everything runs over the graphic card. So lots of things must be done internally and there are some really new design options in co-operation with the layers- and graphics.library for the windows and gadgets. You'll notice these changes immediately on the Workbench. Seen from the programmer's perspective nothing much has changed.

Everything is variable

If you've already clicked yourselves through the GUI-adjuster, you'll know just how many options are at your fingertips to design all the possible GUI elements. For some, there are far too many, but remember all the settings are supposed to end up giving a harmonious big picture. For example, windows can nowadays have shading, the background can display as (half)transparent, the captions can have colour gradients, and the windows can be presented with rounded edges. The width for the window frame used to be practically fixed: now it can be displayed very differently. In theory the left and right margin can have a different width. If you intend to position gadgets in the window frame, you should make them relative. So, if you write a text in the caption, what can occur is that the background colour does not match the rest of the caption.

That's why we'll take a simple Intuition window with sliders in the frame as our first example. This project is also compilable under AmigaOS 3.9 showing you that you don't have to program differently, if you've already made it compatible by default. You must translate the program with "gcc -D__USE_INLINE__ WinSlider.c -o WinSlider -lauto" because of the old denotation. It is due to Define that you can omit the Interface name before the function calls. In the sample program a simple keyboard command with cursor keys is included.

/* WinSlider.c
 *
 * gcc -D__USE_INLINE__ -D__USE_BASETYPE__ WinSlider.c -o WinSlider -l auto
 */
 
/******************************************************************************/
 
#include <exec/types.h>
#include <utility/tagitem.h>
#include <intuition/intuition.h>
 
#include <intuition/classusr.h>
#include <intuition/imageclass.h>
#include <intuition/gadgetclass.h>
#include <intuition/cghooks.h>
#include <intuition/icclass.h>
 
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/utility.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <stdlib.h>
 
#define RAWKEY_CURSORUP    0x4C   /* CURSORUP */
#define RAWKEY_CURSORDOWN  0x4D   /* CURSORDOWN */
#define RAWKEY_CURSORLEFT  0x4F   /* CURSORLEFT */
#define RAWKEY_CURSORRIGHT 0x4E   /* CURSORRIGHT */
 
/******************************************************************************/
 
void cleanup(UBYTE *str);
void goHandleWindow(struct Window *win);
void UpdateSlider(struct Window *win);
 
/******************************************************************************/
 
struct IntuitionBase *IntuitionBase;
struct GfxBase       *GfxBase;
 
/* Prop-Gadget + Richtungs-Pfeile */
struct Gadget *rightpropg;
struct Gadget *uparrowg;
struct Gadget *downarrowg;
 
struct Gadget *bottompropg;
struct Gadget *leftarrowg;
struct Gadget *rightarrowg;
 
/* Images f¸r die Pfeiltasten  */
struct Image  *upimage;
struct Image  *downimage;
struct Image  *leftimage;
struct Image  *rightimage;
 
enum gadgetids
{
  gSliderR =1,
  gUp      =2,
  gDown    =3,
 
  gSliderB =4,
  gLeft    =5,
  gRight   =6,
};
 
LONG currvalr=0,   currvalb=0;     /* Aktuelle Position */
LONG currvalrs=10, currvalbs=10;   /* Anzahl Schritte */
 
/******************************************************************************/
 
void createallandrunit()
{
  struct Gadget   *mygadgets = NULL;
  struct Gadget   *tmpgad;
  struct Window   *win;
  struct DrawInfo *drinfo;
 
  if(!(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",36)))
    cleanup("no V36 intuition library\n");
 
  if(!(GfxBase = (struct GfxBase *) OpenLibrary("graphics.library",36)))
    cleanup("no V36 graphics library\n");
 
  if(!(win = OpenWindowTags(NULL,
      WA_Left,          300,
      WA_Top,            50,
      WA_Width,         240,
      WA_Height,        180,
      WA_Title,         "WinSliders Example",
      WA_Flags,         WFLG_ACTIVATE,
      WA_IDCMP,         IDCMP_GADGETDOWN | IDCMP_GADGETUP |
                        IDCMP_MOUSEMOVE | IDCMP_CLOSEWINDOW |
                        IDCMP_NEWSIZE | IDCMP_VANILLAKEY | IDCMP_RAWKEY,
      WA_SimpleRefresh, TRUE,
      WA_NoCareRefresh, TRUE,
      WA_DepthGadget,   TRUE,
      WA_DragBar,       TRUE,
      WA_CloseGadget,   TRUE,
      WA_SizeGadget,    TRUE,
      WA_SizeBRight,    TRUE,
      WA_SizeBBottom,   TRUE,
      WA_MinWidth,      100,
      WA_MinHeight,     50,
      WA_MaxWidth,      ~0,
      WA_MaxHeight,     ~0,
      TAG_DONE)))
    cleanup( "couldn't open my window.\n");
 
  drinfo = GetScreenDrawInfo(win->WScreen);
 
  /* erzeugen der Pfeil-Symbole */
  upimage = (struct Image *) NewObject(NULL, "sysiclass",
             SYSIA_Size,     0,    /* normal "medium-res" grˆfle */
             SYSIA_Which,    UPIMAGE,
             SYSIA_DrawInfo, drinfo,
             TAG_DONE);
 
  downimage = (struct Image *) NewObject(NULL, "sysiclass",
             SYSIA_Size,     0,    /* normal "medium-res" grˆfle */
             SYSIA_Which,    DOWNIMAGE,
             SYSIA_DrawInfo, drinfo,
             TAG_DONE);
 
  leftimage = (struct Image *) NewObject(NULL, "sysiclass",
             SYSIA_Size,     0,    /* normal "medium-res" Grˆfle */
             SYSIA_Which,    LEFTIMAGE,
             SYSIA_DrawInfo, drinfo,
             TAG_DONE);
 
  rightimage = (struct Image *) NewObject(NULL, "sysiclass",
             SYSIA_Size,     0,    /* normal "medium-res" Grˆfle */
             SYSIA_Which,    RIGHTIMAGE,
             SYSIA_DrawInfo, drinfo,
             TAG_DONE);
 
  /* erzeugen der einzelnen Gadgets */
  tmpgad = (struct Gadget *) &mygadgets;
 
  rightpropg = (struct Gadget *) NewObject(NULL, "propgclass",
               GA_Previous,    tmpgad,
               GA_ID,          gSliderR,
               GA_RelRight,    -13,
               GA_Top,         win->BorderTop + 1,
               GA_Width,       10,
               GA_RelHeight,   -win->BorderTop - win->BorderBottom - upimage->Height - downimage->Height - 2,
               GA_Immediate,   TRUE,
               GA_RelVerify,   TRUE,
               GA_RightBorder, TRUE,
               GA_FollowMouse, TRUE,      /* erzegt IDCMP_MOUSEMOVE */
               PGA_NewLook,    TRUE,
               PGA_Borderless, TRUE,
               PGA_Freedom,    FREEVERT,
               PGA_Top,        0,         /* Nummer des ersten sihtbaren Elements  */
               PGA_Visible,    1,         /* Anzahl der sichtbaren Elemente */
               PGA_Total,      currvalrs, /* Anzahl Stellungen */
               TAG_DONE);
 
  uparrowg = (struct Gadget *) NewObject(NULL, "buttongclass",
               GA_Previous,    rightpropg,
               GA_ID,          gUp,
               GA_Image,       upimage,
               GA_RelRight,    -upimage->Width + 1,
               GA_RelBottom,   -win->BorderBottom - upimage->Height - downimage->Height + 1,
               GA_Width,       upimage->Width,
               GA_Height,      upimage->Height,
               GA_Immediate,   TRUE,
               GA_RelVerify,   TRUE,
               GA_RightBorder,TRUE,
               TAG_DONE);
 
  downarrowg = (struct Gadget *) NewObject(NULL, "buttongclass",
               GA_Previous,    uparrowg,
               GA_ID,          gDown,
               GA_Image,       downimage,
               GA_RelRight,    -downimage->Width + 1,
               GA_RelBottom,   -win->BorderBottom - upimage->Height + 1,
               GA_Width,       upimage->Width,
               GA_Height,      upimage->Height,
               GA_Immediate,   TRUE,
               GA_RelVerify,   TRUE,
               GA_RightBorder,TRUE,
               TAG_DONE);
 
  bottompropg = (struct Gadget *) NewObject(NULL, "propgclass",
               GA_Previous,    downarrowg,
               GA_ID,          gSliderB,
               GA_Left,        5,
               GA_RelBottom,   -7,
               GA_RelWidth,    -win->BorderRight - leftimage->Width - rightimage->Width - 6,
               GA_Height,      6,
               GA_Immediate,   TRUE,
               GA_RelVerify,   TRUE,
               GA_BottomBorder,TRUE,
               GA_FollowMouse, TRUE,      /* erzegt IDCMP_MOUSEMOVE */
               PGA_NewLook,    TRUE,
               PGA_Borderless, TRUE,
               PGA_Freedom,    FREEHORIZ,
               PGA_Top,        0,         /* Nummer des ersten sihtbaren Elements  */
               PGA_Visible,    1,         /* Anzahl der sichtbaren Elemente */
               PGA_Total,      currvalbs, /* Anzahl Stellungen */
               TAG_DONE);
 
  leftarrowg = (struct Gadget *) NewObject(NULL, "buttongclass",
               GA_Previous,    bottompropg,
               GA_ID,          gLeft,
               GA_Image,       leftimage,
               GA_RelRight,    -win->BorderRight - leftimage->Width - rightimage->Width + 1,
               GA_RelBottom,   -win->BorderBottom + 1,
               GA_Width,       leftimage->Width,
               GA_Height,      leftimage->Height,
               GA_Immediate,   TRUE,
               GA_RelVerify,   TRUE,
               GA_BottomBorder,TRUE,
               TAG_DONE);
 
  rightarrowg = (struct Gadget *) NewObject(NULL, "buttongclass",
               GA_Previous,    leftarrowg,
               GA_ID,          gRight,
               GA_Image,       rightimage,
               GA_RelRight,    -win->BorderRight - leftimage->Width + 1,
               GA_RelBottom,   -win->BorderBottom + 1,
               GA_Width,       downimage->Width,
               GA_Height,      downimage->Height,
               GA_Immediate,   TRUE,
               GA_RelVerify,   TRUE,
               GA_BottomBorder,TRUE,
               TAG_DONE);
 
  /* alle Gadgets ins Fenster einh‰ngen */
  AddGList(win, mygadgets, -1, -1, NULL);
  RefreshGList(mygadgets, win, NULL, -1);
 
  /* Nachrichtenschleife */
  goHandleWindow(win);
 
  /* alle Gadgets wieder aus dem Fenster entfernen */
  RemoveGList(win, mygadgets, -1);
  FreeScreenDrawInfo(win->WScreen, drinfo);
  CloseWindow(win);
 
  /* komplette Liste der erzeugten Gadgets freigeben */
  while(mygadgets)
  {
    tmpgad = mygadgets->NextGadget;
    DisposeObject((Object*)mygadgets);
    mygadgets = tmpgad;
  }
 
  /* die Images m¸ssen seperat freigegeben werden */
  DisposeObject((Object*)upimage);
  DisposeObject((Object*)downimage);
  DisposeObject((Object*)leftimage);
  DisposeObject((Object*)rightimage);
 
  cleanup("all done");
}
 
/******************************************************************************/
 
void cleanup(UBYTE *str)
{
  if(str) Printf("%s\n", str);
 
  if(IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
  if(GfxBase)       CloseLibrary((struct Library *)GfxBase);
 
  exit(0);
}
 
/******************************************************************************/
 
void goHandleWindow(struct Window *win)
{
  struct IntuiMessage *imsg;
  struct Gadget *gad;
 
  for(;;)
  {
    WaitPort(win->UserPort);
    while((imsg=(struct IntuiMessage *) GetMsg(win->UserPort)))
    {
      switch(imsg->Class)
      {
        case IDCMP_CLOSEWINDOW:
          ReplyMsg((struct Message *) imsg);
          return;
 
        case IDCMP_GADGETDOWN:
          /* gedr¸cktes Gadget vermerken wenn IDCMP_MOUSEMOVE benutzt werden soll */
          break;
 
        case IDCMP_GADGETUP:
          gad = (struct Gadget *) imsg->IAddress;
 
          /* Pfeil-Gadgets (und Slider) auswerten */
          switch(gad->GadgetID)
          {
            case gSliderR:
                GetAttr(PGA_Top, (Object*)gad, (ULONG*)&currvalr);
Printf("RIGHT %ld\n",currvalr);
                break;
            case gUp:
                if(currvalr > 0) currvalr--;
Printf("RIGHT %ld --\n",currvalr);
                UpdateSlider(win);
                break;
            case gDown:
                if(currvalr < currvalrs-1) currvalr++;
Printf("RIGHT %ld ++\n",currvalr);
                UpdateSlider(win);
                break;
 
            case gSliderB:
                GetAttr(PGA_Top, (Object*)gad, (ULONG*)&currvalb);
Printf("BOTTOM %ld\n",currvalb);
                break;
            case gLeft:
                if(currvalb > 0) currvalb--;
Printf("BOTTOM %ld --\n",currvalb);
                UpdateSlider(win);
                break;
            case gRight:
                if(currvalb < currvalbs-1) currvalb++;
Printf("BOTTOM %ld ++\n",currvalb);
                UpdateSlider(win);
                break;
          }
          break;
 
        /* Tastatureingaben auswerten */
        case IDCMP_RAWKEY:
          if(imsg->Code == RAWKEY_CURSORLEFT)
          {
            if(currvalb > 0) currvalb--;
Printf("BOTTOM %ld --\n",currvalb);
            UpdateSlider(win);
          }
          if(imsg->Code == RAWKEY_CURSORRIGHT)
          {
            if(currvalb < currvalbs-1) currvalb++;
Printf("BOTTOM %ld ++\n",currvalb);
            UpdateSlider(win);
          }
          if(imsg->Code == RAWKEY_CURSORUP)
          {
            if(currvalr > 0) currvalr--;
Printf("RIGHT %ld --\n",currvalr);
            UpdateSlider(win);
          }
          if(imsg->Code == RAWKEY_CURSORDOWN)
          {
            if(currvalr < currvalrs-1) currvalr++;
Printf("RIGHT %ld ++\n",currvalr);
            UpdateSlider(win);
          }
          break;
      }
 
      ReplyMsg((struct Message *) imsg);
    }
  }
}
 
/******************************************************************************/
 
void UpdateSlider(struct Window *win)
{
  SetGadgetAttrs(rightpropg, win, NULL, PGA_Top, currvalr, TAG_DONE);
  SetGadgetAttrs(bottompropg, win, NULL, PGA_Top, currvalb, TAG_DONE);
}
 
/******************************************************************************/
 
int main()
{
  createallandrunit();
 
  return 0;
}
AF106 WinSlider-grab.png

Screens and windows

If you want to, you can move windows now beyond the screen boundaries. You must set the tag SA_OffScreenDragging to TRUE when you open a window. As the tag is not set by default, there can be some undesired side-effects in old programs.

If you want to be able to determine whether you can set a window according to your ideas, you can do it through the list in the intuition.library. It is recommended to turn off the multi-tasking so no-one can change the list while browsing it. There is a new function for it under AmigaOS 4 IIntuition->LockScreenList(). It gives the index to the first screen as a return value. Based on the NextScreen, that is, FirstWindow references you can navigate through the list like before. To unlock the list use - IIntuition->UnlockScreenList() . As you can't either open or close a screen/window during this time, you should use the unlock command as little as possible. We'll find a handy way to implement it in the example "WindowList.c".

/* WindowList.c
 *
 * gcc WindowList.c -o WindowList -l auto
 */
 
/******************************************************************************/
 
#define __USE_BASETYPE__
 
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
 
/******************************************************************************/
 
int main()
{
  struct Screen *scr;
  struct Window *win;
 
  for(scr = IIntuition->LockScreenList(); scr; scr = scr->NextScreen)
  {
    IDOS->Printf("Screen <%.40s> at %ld,%ld with size %ldx%ld\n",
                 (scr->Title ? scr->Title : "unnamed"),
                 scr->LeftEdge,
                 scr->TopEdge,
                 scr->Width,
                 scr->Height
                );
 
    for(win = scr->FirstWindow; win; win = win->NextWindow)
    {
      IDOS->Printf("  Window <%.40s> at %ld,%ld with size %ld,%ld\n",
                   (win->Title ? win->Title : "unnamed"),
                   win->LeftEdge,
                   win->TopEdge,
                   win->Width,
                   win->Height
                  );
    }
  }
  IIntuition->UnlockScreenList();
 
  return 0;
}
AF106 WindowList-grab.png

You can automatically create a message port in windows, or create it dynamically too if you have several windows. In a drawing program or a text editor, for instance, you must manually create a message port and give it to every window. When you close a window you must make sure that there are no more entries for that window in the message bar. If you set the tag WA_UserPort with a message port when you open a window, Intuition immediately takes care of it so that it is nicely left. But you still have to do the programming to create and de-allocate the actual message port.

A new tag for windows is WA_Hidden. You can use it to create windows that are not visible. As this option doesn't seem to make much sense there are two functions IIntuition->ShowWindow() and Iintuition->HideWindow() that enable you to show and hide a window. The whole thing works the other way around too; if you don't need a window at the moment, but you don't want to close it. Unlike the present Iconify options the window remains entirely in memory at this point and so all the pointers are valid too. We also created a mini program "HideWindow.c" for this purpose as well. You can start it from the console, show the window with CTRL-E, hide it with CTRL-F and close the program with CTRL-C. The nextWindowList below shows you that there is a window even though it is not visible.

/* HideWindow.c
 *
 * gcc HideWindow.c -o HideWindow -l auto
 */
 
#include <dos/dos.h>
#include <utility/tagitem.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
 
int main()
{
  struct Window *win;
 
  if((win = IIntuition->OpenWindowTags(NULL,
                       WA_Title,  "HideWindow Example",
                       WA_Hidden, TRUE,  /* create but not show */
                       WA_Left,   100,
                       WA_Top,    100,
                       WA_Width,  300,
                       WA_Height, 200,
                       TAG_END)))
  {
    for(;;)
    {
      const ULONG signal = IExec->Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F);
      if(signal == SIGBREAKF_CTRL_C) break;
      else if(signal == SIGBREAKF_CTRL_E) IIntuition->ShowWindow(win,WINDOW_FRONTMOST);
      else if(signal == SIGBREAKF_CTRL_F) IIntuition->HideWindow(win);
    }
 
    IIntuition->CloseWindow(win);
  }
  else IDOS->Printf("Error: window can not created\n");
 
  return( 0 );
}
AF106 WindowListHidden-grab.png

EasyRequester

Programmers can use EasyRequesters to give a user feedback or to make queries with several options. The "EasyStruct" has been expanded so it now can be used even more flexibly. For example, previously the window was always opened top left and on the Workbench. You could change this if you passed a window pointer, which was only possible if you already had an open window on your own screen. For this case there is now the entry es_Screen that must be used in combination with es_Flag = ESF_SCREEN. Additionally, you can also pass a taglist with es_TagList. In order to be considered you must enable it with es_Flag = ESF_TAGGED. There is so far only one possible tag for the position of the window with ESA_Position:

REQPOS_DEFAULT use Prefs settings
REQPOS_CORNER top left on the screen
REQPOS_BELOWBAR top left underneath the screen caption
REQPOS_CENTERMOUSE in the centre underneath the mouse
REQPOS_CENTERSCREEN in the centre of the screen
REQPOS_CENTERWINDOW in the centre of the active window

You can find the practical use in the code example "EasyRequester.c".

/* EasyRequester.c
 *
 * gcc EasyRequester.c -o EasyRequester -l auto
 */
 
/******************************************************************************/
 
#define __USE_BASETYPE__
 
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <stdarg.h>
 
/******************************************************************************/
 
int32 EasyRequester(CONST_STRPTR text, CONST_STRPTR button, ...)
{
  struct TagItem tags[] = { ESA_Position, REQPOS_CENTERSCREEN, TAG_END };
  struct EasyStruct easyreq = { 0 };
 
  static TEXT textbuffer[1024];
 
  va_list parameter;
  va_start(parameter,button);
  vsprintf(textbuffer,text,parameter);
  va_end(parameter);
 
  easyreq.es_StructSize   = sizeof(struct EasyStruct);
  easyreq.es_Flags        = ESF_SCREEN | ESF_TAGGED | ESF_EVENSIZE;
  easyreq.es_Title        = "EasyRequester - Example";
  easyreq.es_TextFormat   = textbuffer;
  easyreq.es_GadgetFormat = button;
  easyreq.es_Screen       = IntuitionBase->ActiveScreen;
  easyreq.es_TagList      = tags;
 
  return IIntuition->EasyRequestArgs(NULL, &easyreq, NULL, NULL);
}
 
/******************************************************************************/
 
int main()
{
  int res = EasyRequester("EasyRequester with variable arguments:\n%s %ld.%ld",
                          "Continue|Cancel",
                          IntuitionBase->LibNode.lib_Node.ln_Name,
                          IntuitionBase->LibNode.lib_Version,
                          IntuitionBase->LibNode.lib_Revision
                         );
 
  return res;
}
AF106 EasyRequester-grab.png

The forgotten requester.class

The requester.class was already introduced with AmigaOS 2 in-line with the BOOPSI concept. But because of the EasyRequester it hardly gained any attention. With AmigaOS 4 the class has been upgraded significantly offering new possibilities and tags.

Using REQ_Type you can select four predefined types:

  1. REQTYPE_INFO (value 0) = Information/Query
  2. REQTYPE_INTEGER (value 1) = number input
  3. REQTYPE_STRING (value 2) = text input
  4. REQTYPE_PROGRESS (value 3) = progress bar (not yet implemented)

The Tag REQ_Image is particularly interesting. It allows the use of predefined symbols that are shown in the requester (on the left). The following symbols are available:

  • REQIMAGE_DEFAULT = empty
  • REQIMAGE_INFO = show information
  • REQIMAGE_WARNING = warning, hints
  • REQIMAGE_ERROR = error, program abort
  • REQIMAGE_QUESTION = in a query
  • REQIMAGE_INSERTDISK = demand disk

Alternatively, you can also use your own image (of type struct Image *). All the options are summarised in the example "Requester.c".

/* Requester.c
 *
 * gcc -D__USE_INLINE__ -D__USE_BASETYPE__ Requester.c -o Requester -l auto
 */
 
/******************************************************************************/
 
#include <classes/requester.h>
#include <intuition/intuitionbase.h>
 
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/requester.h>
#include <clib/alib_protos.h>
 
struct Library       *RequesterBase;
struct IntuitionBase *IntuitionBase;
 
/******************************************************************************/
 
int main()
{
  Object *reqObj, *intObj, *strObj, *progObj;
  UBYTE buffer[11] = "default";
 
  if((IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 40)))
  {
    if((RequesterBase = OpenLibrary("requester.class", 40)))
    {
      if(!(reqObj = NewObject(NULL, "requester.class",
                   REQ_Type,       REQTYPE_INFO,
                   REQ_TitleText,  "Request",
                   REQ_BodyText,   "Please select the request type\nyou will test.",
                   REQ_GadgetText, "_Integer|"
                                   "_String|"
//                                   "_Progress|"
                                   "_Cancel",
                   TAG_END)))
        Printf("Error: info - requester object cannot created !\n");
 
      if(!(intObj = NewObject(NULL, "requester.class",
                   REQ_Type,       REQTYPE_INTEGER,
                   REQ_TitleText,  "Integer-Request",
                   REQ_BodyText,   "Enter an integer ...",
                   REQ_GadgetText, "C_ontinue|_Cancel",
                   REQI_Minimum,    1,
                   REQI_Maximum,    99999999,
                   REQI_Invisible,  FALSE,
                   REQI_Number,     12345678,
                   REQI_Arrows,     TRUE,
                   REQI_MaxChars,   8,
                   TAG_END)))
        Printf("Error: integer - request object cannot created !\n");
 
      if(!(strObj = NewObject(NULL, "requester.class",
                   REQ_Type,       REQTYPE_STRING,
                   REQ_TitleText,  "String-Request",
                   REQ_BodyText,   "Enter a string ...",
                   REQ_GadgetText, "C_ontinue|_Cancel",
                   REQS_Invisible,   FALSE,
                   REQS_Buffer,      buffer,
                   REQS_ShowDefault, TRUE,
                   REQS_MaxChars,    10,
                   //REQS_ChooserArray
                   //REQS_ChooserActive
                   TAG_END)))
        Printf("Error: string - requester object cannot created !\n");
 
//      if(!(progObj = NewObject(NULL, "requester.class",
//                   REQ_Type,       REQTYPE_PROGRESS,
//                   REQ_TitleText,  "Progressbar-Request",
//                   REQ_BodyText,   "Show the progressbar filling ...",
//                   REQ_GadgetText, "C_ontinue|_Cancel",
//                   REQP_Total,        100,
//                   REQP_Current,      25,
//                   REQP_AbortText,    "Cancel filling",
//                   REQP_ProgressText, "Show the progressbar filling ...",
//                   //REQP_OpenInactive
//                   //REQP_NoText
//                   //REQP_Dynamic
//                   REQP_CenterWindow, TRUE,
//                   REQP_LastPosition, FALSE,
//                   REQP_Percent,      TRUE,
//                   REQP_Ticks,        10,
//                   REQP_ShortTicks,   TRUE,
//                   TAG_END)))
//        Printf("Error: progress - requester object cannot created !\n");
 
 
      if(reqObj)
      {
        struct orRequest my_orRequest = { RM_OPENREQ, NULL, IntuitionBase->ActiveWindow, NULL };
        BOOL running = TRUE;
 
        while(running)
        {
          switch(DoMethodA(reqObj, (Msg)&my_orRequest))
          {
            case 1: if(intObj && DoMethodA(intObj, (Msg)&my_orRequest) != 1) running = FALSE;
                    break;
            case 2: if(strObj && DoMethodA(strObj, (Msg)&my_orRequest) != 1) running = FALSE;
                    break;
//            case 3: if(progObj && DoMethodA(progObj, (Msg)&my_orRequest) != 1) running = FALSE;
//                    break;
            default: running = FALSE; break;
          }
        }
      }
 
      if(reqObj) DisposeObject(reqObj);
      if(intObj) DisposeObject(intObj);
      if(strObj) DisposeObject(strObj);
//      if(progObj) DisposeObject(progObj);
 
      CloseLibrary(RequesterBase);
    }
    else Printf("Error: requester.class V40 cannot opened !\n");
 
    CloseLibrary((struct Library *)IntuitionBase);
  }
  else Printf("Error: intuition.library V40 cannot opened !\n");
 
  return 0;
}
AF106 Requester-grab.png

Mouse wheel

Nowadays a computer mouse can have one, or several wheels, that you can use in order to scroll through a document, for example, without having to press and move the scroller. So you can perform this action without having to physically move the mouse. The general support is already implemented in AmigaOS, in your own program there is an option for you to ensure that you have context-dependent support.

For this you need to set the IDCMP-Flag on IDCMP_EXTENDEDMOUSE when you create a window. This flag shows up when you move the mouse wheel and is also set in the code field IMSGCODE_INTUIWHEELDATA. Over the IAdress pointer you can get the IntuiWheelData structure where increments for up to two mouse wheels can be readout (X=mousewheel 1 and Y=mousewheel 2). However, there is a fly in the ointment, because if you create the window with window.class, as is usually the case in current applications, there is still no support for it, and you must attach a WINDOW_IDCMPHook additionally in order to be able to analyze the message.

As not all mice have two wheels, but the program provides two possibilities in some situations (e.g. scroll up/down or left/right browser window content), you can solve this problem with an additionally pressed key. For example, if you hold the CTRL-key pressed, then you can simulate the movement of the mousewheel 2 with a movement of the mousewheel 1. So far there is no general recommendation or setting in the operating system for this situation. A possible implementation is to be found in the example "MouseWheelTest.c".

/* MouseWheelTest.c
 *
 * gcc MouseWheelTest.c -o MouseWheelTest -l auto
 */
 
/******************************* INCLUDES *************************************/
 
#include <exec/types.h>
#include <intuition/intuition.h>
 
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/utility.h>
#include <proto/utility.h>
 
#include <string.h>
 
/******************************************************************************/
 
void DisplayMsg(struct Window *win, int16 wx, int16 wy, CONST_STRPTR text)
{
  static TEXT buffer[20];
 
  IUtility->SNPrintf(buffer,sizeof(buffer),"wheel x=%2ld y=%2ld", wx, wy);
  IGraphics->Move(win->RPort, 20, 50);
  IGraphics->Text(win->RPort, buffer, strlen(buffer));
  IGraphics->Move(win->RPort, 20, 65);
  IGraphics->Text(win->RPort, text, strlen(text));
}
 
/******************************************************************************/
 
int main(int argc, char *argv[])
{
  struct Window *win;
  struct IntuiMessage *imsg;
  BOOL laufen = TRUE;
 
  /* create intuition window */
  if((win = IIntuition->OpenWindowTags(NULL,
      WA_Left,              40,
      WA_Top,               40,
      WA_InnerWidth,        200,
      WA_InnerHeight,       60,
      WA_Title,             "MouseWheel Example",
      WA_IDCMP,             IDCMP_CLOSEWINDOW |
                            IDCMP_MOUSEMOVE |
                            IDCMP_MOUSEBUTTONS |
                            IDCMP_EXTENDEDMOUSE,
      WA_SmartRefresh,      TRUE,
      WA_DepthGadget,       TRUE,
      WA_DragBar,           TRUE,
      WA_CloseGadget,       TRUE,
      WA_Activate,          TRUE,
      WA_RMBTrap,           TRUE,
      WA_ReportMouse,       TRUE,
      TAG_DONE)))
  {
    IGraphics->SetAPen(win->RPort, 1);
    IGraphics->SetDrMd(win->RPort, JAM2);
    DisplayMsg(win, 0, 0, "            ");
 
    while(laufen)
    {
      /* wait for signals */
      const ULONG sigs = IExec->Wait(1 << win->UserPort->mp_SigBit | SIGBREAKF_CTRL_C);
 
      /* get intuition message */
      while((imsg=(struct IntuiMessage *) IExec->GetMsg(win->UserPort)))
      {
        switch(imsg->Class)
        {
          case IDCMP_CLOSEWINDOW:
            /* close window */
            laufen = FALSE;
            break;
 
          case IDCMP_MOUSEMOVE:
            /* mouse was moved */
            DisplayMsg(win, 0, 0, "IDCMP_MOUSEMOVE   ");
            break;
 
          case IDCMP_MOUSEBUTTONS:
            /* mouse button was pressed */
            DisplayMsg(win, 0, 0, "IDCMP_MOUSEBUTTONS");
            break;
 
          case IDCMP_EXTENDEDMOUSE:
            {
              /* mouse wheel */
              if(imsg->Code == IMSGCODE_INTUIWHEELDATA)
              {
                struct IntuiWheelData *data = (struct IntuiWheelData *) imsg->IAddress;
                if(data->Version == INTUIWHEELDATA_VERSION)
                {
                  if(imsg->Qualifier & IEQUALIFIER_CONTROL)
                  {
                    /* pressed CTRL/STRG-qualifier will changed wheels */
                    const WORD merk = data->WheelX;
                    data->WheelX = data->WheelY;
                    data->WheelY = merk;
                  }
 
                  DisplayMsg(win, data->WheelX, data->WheelY, "IDCMP_EXTENTMOUSE ");
                }
              }
            }
            break;
        }
 
        /* replay message to intuition */
        IExec->ReplyMsg((struct Message *) imsg);
      }
 
      /* CTRL-C with quit the program */
      if(sigs & SIGBREAKF_CTRL_C) laufen = FALSE;
    }
 
    /* close window */
    IIntuition->CloseWindow(win);
  }
  else IDOS->Printf("Error: can not create window\n");
 
  return 0;
}
AF106 MouseWheelTest-grab.png

Further changes

The BOOPSI classes have now received the official type "struct ClassLibrary *" too and have now their own functions for opening and closing. Previously, you had to resort to Iexec->OpenLibrary()/IExec->CloseLibrary() for this purpose, and in some cases search in different directories as well. Besides, the function IIntuition->OpenClass() returns the class pointer in the third argument. You can rely on this in all system classes; in other developments you must definitely check the pointer. If you are not in the mood for it, you can simply enter "-l auto" and most required BOOPSI gadgets, images and classes are automatically opened from the startup-code.

There are also new functions to set and determine window and screen attributes too. In future you won't have to read or change screen/window structures, but there will be a normalised interface that will take care of it. So far only a part of the SA_xxx and WA_xxx tags can be used for it. The function names are IIntuition->GetScreenAttr()/IIntuition->SetScreenAttr() for screens, i.e., IIntuition->GetWindowAttr()/IIntuition->SetWindowAttr() for windows.

Rainbow

So, before we finish this part, we'll use some colours. There is now a function in Intuition, with which you can draw a colour gradient. You must fill out a structure GradientSpec (from intuition/intuition.h) for this. Primarily, these are, the RGB start value, and RGB end value for the gradient, and an angle. The angle (in the 0-359 degree range) must be converted before with IIntuition->DirectionVector(). The actual drawing in the rastport stating the size is done by IIntuition->DrawGradient(). Under "GradientPrg.c" you'll find a practical example that draws the gradient of type COLOR and allows the colour value setting. You can take over the window in your own projects too if the option for the colour gradient selection is given.

/* Michael Christoph
 *
 * GradientPrg.c
 *
 * gcc GradientPrg.c -o GradientPrg -l auto
 */
 
/******************************************************************************/
 
#include <intuition/gadgetclass.h>
#include <intuition/icclass.h>
#include <classes/window.h>
#include <reaction/reaction_macros.h>
#include <libraries/gadtools.h>
#include <gadgets/checkbox.h>
#include <gadgets/slider.h>
#include <gadgets/space.h>
#include <gadgets/integer.h>
#include <images/label.h>
 
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/utility.h>
#include <proto/window.h>
#include <proto/layout.h>
#include <proto/button.h>
#include <proto/slider.h>
#include <proto/space.h>
#include <proto/label.h>
 
#define MENU_ID_Quit       FULLMENUNUM(0,0,NOSUB)
 
#define GAD_ID_SRed        1
#define GAD_ID_SGreen      2
#define GAD_ID_SBlue       3
#define GAD_ID_ERed        4
#define GAD_ID_EGreen      5
#define GAD_ID_EBlue       6
#define GAD_ID_Degrees     7
#define GAD_ID_Preview     8
 
Object        *gb_WindowObj;
struct Window *gb_Win;
struct Gadget *gb_MainLayout;
struct Gadget *gb_OkGad;
struct Gadget *gb_CancelGad;
struct Gadget *gb_PreviewGad;
struct Gadget *gb_SRedGad;
struct Gadget *gb_SGreenGad;
struct Gadget *gb_SBlueGad;
struct Gadget *gb_ERedGad;
struct Gadget *gb_EGreenGad;
struct Gadget *gb_EBlueGad;
struct Gadget *gb_DegreesGad;
 
Object        *gb_Model;
Object        *gb_ICSliderSR;
Object        *gb_ICSliderSG;
Object        *gb_ICSliderSB;
Object        *gb_ICSliderER;
Object        *gb_ICSliderEG;
Object        *gb_ICSliderEB;
 
struct GradientSpec  gb_Gradspec;
struct Hook          gb_RenderHook;
struct Hook          gb_IDCMPHook;
 
struct TagItem MapInteger2Integer[] = { INTEGER_Number, INTEGER_Number, TAG_END };
struct TagItem MapSlider2Integer[]  = { SLIDER_Level,   INTEGER_Number, TAG_END };
 
static const char* version USED = "\0$VER: GradientPrg 1.00 (18.07.2013) - Copyright (c) Jul.2013 by Meicky-Soft\n";
 
/******************************************************************************/
 
void RedrawGradient()
{
  ULONG val;
 
  /* die aktuellen Sliderpositionen ermitteln */
  IIntuition->GetAttr(SLIDER_Level,(Object*)gb_SRedGad,(ULONG*)&val);
 	gb_Gradspec.Specs.Abs.RGBStart[0] = val;
  IIntuition->GetAttr(SLIDER_Level,(Object*)gb_SGreenGad,(ULONG*)&val);
 	gb_Gradspec.Specs.Abs.RGBStart[1] = val;
  IIntuition->GetAttr(SLIDER_Level,(Object*)gb_SBlueGad,(ULONG*)&val);
 	gb_Gradspec.Specs.Abs.RGBStart[2] = val;
  IIntuition->GetAttr(SLIDER_Level,(Object*)gb_ERedGad,(ULONG*)&val);
  gb_Gradspec.Specs.Abs.RGBEnd[0]   = val;
  IIntuition->GetAttr(SLIDER_Level,(Object*)gb_EGreenGad,(ULONG*)&val);
 	gb_Gradspec.Specs.Abs.RGBEnd[1]   = val;
  IIntuition->GetAttr(SLIDER_Level,(Object*)gb_EBlueGad,(ULONG*)&val);
 	gb_Gradspec.Specs.Abs.RGBEnd[2]   = val;
  IIntuition->GetAttr(SLIDER_Level,(Object*)gb_DegreesGad,(ULONG*)&val);
   gb_Gradspec.Direction = IIntuition->DirectionVector(val);
 
  /* und das Vorschaufeld aktualisieren */
  IIntuition->RefreshGadgets(gb_PreviewGad,gb_Win,NULL);
}
 
/******************************************************************************/
 
void RenderHookFunc(struct Hook *hook, Object *obj, struct gpRender *gpr)
{
  /*
  ** Hook-Funktion zum Zeichnen des Farbverlaufs
  */
 
  struct IBox *gb_DrawArea; 
 
  /* die Grˆfle unseres Ausgabebereiches ermitteln */
  IIntuition->GetAttr(SPACE_AreaBox,(Object*)gb_PreviewGad,(ULONG *)&gb_DrawArea);
 
  /* nur wenn das Fenster sichtbar ist, d¸rfen wir hineinzeichnen */
  if(gb_Win)
  {
    IIntuition->DrawGradient(gpr->gpr_RPort,gb_DrawArea->Left,gb_DrawArea->Top,
                             gb_DrawArea->Width-1,gb_DrawArea->Height-1,
                             NULL,0,&gb_Gradspec,gpr->gpr_GInfo->gi_DrInfo);
  }
}
 
/******************************************************************************/
 
void IDCMPHookFunc(struct Hook *hook, Object *winobj, struct IntuiMessage *msg)
{
  /*
  ** Hook-Funktion zum Abhˆren der IDCMP_UPDATE-Nachrichten
  ** wird erzeugt w‰hrend ein Slider bewegt wird
  */
 
  if(msg->Class == IDCMP_IDCMPUPDATE)
  {
    struct TagItem *taglist = (struct TagItem *) msg->IAddress;
 
    /* uns interessieren nur eigene Nachrichten mit gesetztem INTEGER_Number Tag */
    if(IUtility->GetTagData(INTEGER_Number,-1,taglist) != -1)
    {
      RedrawGradient();
    }
  }
}
 
/******************************************************************************/
 
int main()
{
  /* Gradient-Struktur vorbelegen */
  gb_Gradspec.Mode = GRADMODE_COLOR;
  gb_Gradspec.Direction = IIntuition->DirectionVector(0);
 
  /* RenderHook initialisieren */
  gb_RenderHook.h_Entry    = (ULONG (*)())RenderHookFunc;
  gb_RenderHook.h_SubEntry = NULL;
 
  /* IDCMPHook initialisieren zum Abhˆren der IDCMP_UPDATE-Nachrichten */
  gb_IDCMPHook.h_Entry    = (ULONG (*)())IDCMPHookFunc;
  gb_IDCMPHook.h_SubEntry = NULL;
 
  /* Sender-Model, dass den IDCMP_IDCMPUPDATE auslˆst */
  gb_Model = (Object *) IIntuition->NewObject(NULL,MODELCLASS,
                                  ICA_MAP,    MapInteger2Integer,
                                  ICA_TARGET, ICTARGET_IDCMP,
                                  TAG_END);
 
 
    /* alle Gadgets erzeugen */
    if((gb_PreviewGad = (struct Gadget *) IIntuition->NewObject(ISpace->SPACE_GetClass(),NULL,
        GA_ID,                GAD_ID_Preview,
        SPACE_MinWidth,       50,
        SPACE_MinHeight,      50,
        SPACE_Transparent,    FALSE,
        SPACE_BevelStyle,     BVS_FIELD,
        SPACE_RenderHook,     &gb_RenderHook,
        TAG_END)))
    {
    if((gb_SRedGad = (struct Gadget *) IIntuition->NewObject(ISlider->SLIDER_GetClass(),NULL,
        GA_ID,                GAD_ID_SRed,
        GA_RelVerify,         TRUE,
        GA_Immediate,         TRUE,
        ICA_MAP,              MapSlider2Integer,
        ICA_TARGET,           gb_Model,
        SLIDER_Min,           0,
        SLIDER_Max,           255,
        SLIDER_Level,         0,
        SLIDER_Ticks,         16,
        SLIDER_KnobDelta,     16,
        SLIDER_LevelFormat,   "%ld",
        SLIDER_LevelPlace,    PLACETEXT_IN,
        SLIDER_LevelJustify,  SLJ_CENTER,
        SLIDER_Orientation,   SLIDER_HORIZONTAL,
        TAG_END)))
    {
    if((gb_SGreenGad = (struct Gadget *) IIntuition->NewObject(ISlider->SLIDER_GetClass(),NULL,
        GA_ID,                GAD_ID_SGreen,
        GA_RelVerify,         TRUE,
        GA_Immediate,         TRUE,
        ICA_MAP,              MapSlider2Integer,
        ICA_TARGET,           gb_Model,
        SLIDER_Min,           0,
        SLIDER_Max,           255,
        SLIDER_Level,         0,
        SLIDER_Ticks,         16,
        SLIDER_KnobDelta,     16,
        SLIDER_LevelFormat,   "%ld",
        SLIDER_LevelPlace,    PLACETEXT_IN,
        SLIDER_LevelJustify,  SLJ_CENTER,
        SLIDER_Orientation,   SLIDER_HORIZONTAL,
        TAG_END)))
    {
    if((gb_SBlueGad = (struct Gadget *) IIntuition->NewObject(ISlider->SLIDER_GetClass(),NULL,
        GA_ID,                GAD_ID_SBlue,
        GA_RelVerify,         TRUE,
        GA_Immediate,         TRUE,
        ICA_MAP,              MapSlider2Integer,
        ICA_TARGET,           gb_Model,
        SLIDER_Min,           0,
        SLIDER_Max,           255,
        SLIDER_Level,         0,
        SLIDER_Ticks,         16,
        SLIDER_KnobDelta,     16,
        SLIDER_LevelFormat,   "%ld",
        SLIDER_LevelPlace,    PLACETEXT_IN,
        SLIDER_LevelJustify,  SLJ_CENTER,
        SLIDER_Orientation,   SLIDER_HORIZONTAL,
        TAG_END)))
    {
    if((gb_ERedGad = (struct Gadget *) IIntuition->NewObject(ISlider->SLIDER_GetClass(),NULL,
        GA_ID,                GAD_ID_ERed,
        GA_RelVerify,         TRUE,
        GA_Immediate,         TRUE,
        ICA_MAP,              MapSlider2Integer,
        ICA_TARGET,           gb_Model,
        SLIDER_Min,           0,
        SLIDER_Max,           255,
        SLIDER_Level,         0,
        SLIDER_Ticks,         16,
        SLIDER_KnobDelta,     16,
        SLIDER_LevelFormat,   "%ld",
        SLIDER_LevelPlace,    PLACETEXT_IN,
        SLIDER_LevelJustify,  SLJ_CENTER,
        SLIDER_Orientation,   SLIDER_HORIZONTAL,
        TAG_END)))
    {
    if((gb_EGreenGad = (struct Gadget *) IIntuition->NewObject(ISlider->SLIDER_GetClass(),NULL,
        GA_ID,                GAD_ID_EGreen,
        GA_RelVerify,         TRUE,
        GA_Immediate,         TRUE,
        ICA_MAP,              MapSlider2Integer,
        ICA_TARGET,           gb_Model,
        SLIDER_Min,           0,
        SLIDER_Max,           255,
        SLIDER_Level,         0,
        SLIDER_Ticks,         16,
        SLIDER_KnobDelta,     16,
        SLIDER_LevelFormat,   "%ld",
        SLIDER_LevelPlace,    PLACETEXT_IN,
        SLIDER_LevelJustify,  SLJ_CENTER,
        SLIDER_Orientation,   SLIDER_HORIZONTAL,
        TAG_END)))
    {
    if((gb_EBlueGad = (struct Gadget *) IIntuition->NewObject(ISlider->SLIDER_GetClass(),NULL,
        GA_ID,                GAD_ID_EBlue,
        GA_RelVerify,         TRUE,
        GA_Immediate,         TRUE,
        ICA_MAP,              MapSlider2Integer,
        ICA_TARGET,           gb_Model,
        SLIDER_Min,           0,
        SLIDER_Max,           255,
        SLIDER_Level,         0,
        SLIDER_Ticks,         16,
        SLIDER_KnobDelta,     16,
        SLIDER_LevelFormat,   "%ld",
        SLIDER_LevelPlace,    PLACETEXT_IN,
        SLIDER_LevelJustify,  SLJ_CENTER,
        SLIDER_Orientation,   SLIDER_HORIZONTAL,
        TAG_END)))
    {
    if((gb_DegreesGad = (struct Gadget *) IIntuition->NewObject(ISlider->SLIDER_GetClass(),NULL,
        GA_ID,                GAD_ID_Degrees,
        GA_RelVerify,         TRUE,
        GA_Immediate,         TRUE,
        ICA_MAP,              MapSlider2Integer,
        ICA_TARGET,           gb_Model,
        SLIDER_Min,           0,
        SLIDER_Max,           359,
        SLIDER_Level,         0,
        SLIDER_Ticks,         8,
        SLIDER_KnobDelta,     15,
        SLIDER_LevelFormat,   "%ld",
        SLIDER_LevelPlace,    PLACETEXT_RIGHT,
        //SLIDER_LevelJustify,  SLJ_CENTER,
        SLIDER_Orientation,   SLIDER_HORIZONTAL,
        TAG_END)))
    {
 
      /* das Fenster-Objekt erzeugen */
      if((gb_WindowObj = (Object *) IIntuition->NewObject(IWindow->WINDOW_GetClass(),NULL,
        WA_IDCMP,             IDCMP_GADGETUP | IDCMP_GADGETDOWN | IDCMP_MOUSEMOVE |
                              IDCMP_CLOSEWINDOW | IDCMP_IDCMPUPDATE,
        WA_SizeGadget,        TRUE,
        WA_DepthGadget,       TRUE,
        WA_DragBar,           TRUE,
        WA_CloseGadget,       TRUE,
        WA_Activate,          TRUE,
        WA_Title,             "Configure Gradient ...",
        WINDOW_Position,      WPOS_CENTERSCREEN,
        WINDOW_IDCMPHook,     &gb_IDCMPHook,
        WINDOW_IDCMPHookBits, IDCMP_IDCMPUPDATE,
 
        /* das Layout-Object erzeugen und im Fenster einh‰ngen */
        WINDOW_ParentGroup,   gb_MainLayout = (struct Gadget *)
                          IIntuition->NewObject(ILayout->LAYOUT_GetClass(),NULL,
          LAYOUT_Orientation,  LAYOUT_ORIENT_VERT,
          LAYOUT_SpaceOuter,   TRUE,
          LAYOUT_SpaceInner,   TRUE,
 
 
          LAYOUT_AddChild, IIntuition->NewObject(ILayout->LAYOUT_GetClass(),NULL,
            LAYOUT_Orientation,  LAYOUT_ORIENT_HORIZ,
 
            /* links das Vorschaufeld */
            LAYOUT_AddChild, IIntuition->NewObject(ILayout->LAYOUT_GetClass(),NULL,
              LAYOUT_Orientation,  LAYOUT_ORIENT_VERT,
              LAYOUT_SpaceInner,   TRUE,
              LAYOUT_AddChild,     gb_PreviewGad,
              TAG_END),
              CHILD_WeightedWidth, 10,
              CHILD_MinWidth, 100,
 
            LAYOUT_AddChild, IIntuition->NewObject(ILayout->LAYOUT_GetClass(),NULL,
              LAYOUT_Orientation,  LAYOUT_ORIENT_VERT,
              LAYOUT_SpaceOuter,   TRUE,
 
              /* daneben die Einstellungen */
              LAYOUT_AddChild, IIntuition->NewObject(ILayout->LAYOUT_GetClass(),NULL,
                LAYOUT_Orientation,  LAYOUT_ORIENT_HORIZ,
                LAYOUT_SpaceInner,   TRUE,
 
                /* erst die Einsteller f¸r die Start-Farbe */
                LAYOUT_AddChild, IIntuition->NewObject(ILayout->LAYOUT_GetClass(),NULL,
                  LAYOUT_Orientation,  LAYOUT_ORIENT_VERT,
                  LAYOUT_SpaceOuter,   TRUE,
                  LAYOUT_SpaceInner,   TRUE,
                  LAYOUT_AddChild,     gb_SRedGad,
                  LAYOUT_Label,        "Start Color",
 
                  CHILD_Label,         IIntuition->NewObject(ILabel->LABEL_GetClass(),NULL,
                                       LABEL_Text, "R:",
                                       TAG_END),
                  LAYOUT_AddChild,     gb_SGreenGad,
                  CHILD_Label,         IIntuition->NewObject(ILabel->LABEL_GetClass(),NULL,
                                       LABEL_Text, "G:",
                                       TAG_END),
                  LAYOUT_AddChild,     gb_SBlueGad,
                  CHILD_Label,         IIntuition->NewObject(ILabel->LABEL_GetClass(),NULL,
                                       LABEL_Text, "B:",
                                       TAG_END),
                  TAG_END),
                  CHILD_WeightedWidth, 35,
 
                /* und daneben die Einsteller f¸r die End-Farbe */
                LAYOUT_AddChild, IIntuition->NewObject(ILayout->LAYOUT_GetClass(),NULL,
                  LAYOUT_Orientation,  LAYOUT_ORIENT_VERT,
                  LAYOUT_SpaceOuter,   TRUE,
                  LAYOUT_SpaceInner,   TRUE,
                  LAYOUT_Label,        "End Color",
 
                  LAYOUT_AddChild,     gb_ERedGad,
                  CHILD_Label,         IIntuition->NewObject(ILabel->LABEL_GetClass(),NULL,
                                       LABEL_Text, "R:",
                                       TAG_END),
                  LAYOUT_AddChild,     gb_EGreenGad,
                  CHILD_Label,         IIntuition->NewObject(ILabel->LABEL_GetClass(),NULL,
                                       LABEL_Text, "G:",
                                       TAG_END),
                  LAYOUT_AddChild,     gb_EBlueGad,
                  CHILD_Label,         IIntuition->NewObject(ILabel->LABEL_GetClass(),NULL,
                                       LABEL_Text, "B:",
                                       TAG_END),
                  TAG_END),
                  CHILD_WeightedWidth, 35,
                TAG_END),
                CHILD_WeightedHeight, 10,
 
            /* und unter den Farbeinstellern der Winkel-Schieber */
            LAYOUT_AddChild, IIntuition->NewObject(ILayout->LAYOUT_GetClass(),NULL,
              LAYOUT_Orientation,  LAYOUT_ORIENT_HORIZ,
              LAYOUT_AddChild,     gb_DegreesGad,
              CHILD_Label,         IIntuition->NewObject(ILabel->LABEL_GetClass(),NULL,
                                   LABEL_Text, "Degrees:",
                                   TAG_END),
              TAG_END),
              CHILD_WeightedHeight, 2,
 
 
            TAG_END),
            CHILD_WeightedWidth, 20,
 
            TAG_END),
 
          TAG_END),
        TAG_END)))
      {
        /* das Fenster ˆffnen */
        if((gb_Win = RA_OpenWindow(gb_WindowObj)))
        {
          /* nach dem ˆffnen muss noch das Vorschaufeld gezeichnet werden */
          IIntuition->RefreshGadgets(gb_PreviewGad,gb_Win,NULL);
 
          /* Signalbit des Fensters erfragen */
          ULONG winsig;
          IIntuition->GetAttr(WINDOW_SigMask,gb_WindowObj,&winsig);
 
          BOOL laufen = TRUE;
          while(laufen)
          {
            ULONG result, code;
 
            /* warten auf Benutzeraktionen */
            const ULONG sigs = IExec->Wait(winsig | SIGBREAKF_CTRL_C);
 
            /* die eingetroffenen Nachrichten verarbeiten */
            while((result = RA_HandleInput(gb_WindowObj,&code)) != WMHI_LASTMSG)
            {
              /* den Nachrichtenanteil ausmaskieren ! */
              switch(result & WMHI_CLASSMASK)
              {
                /* Gadget-Nachrichten auswerten */
                case WMHI_GADGETUP:
                     switch(result & WMHI_GADGETMASK)
                     {
                       case GAD_ID_SRed:
                       case GAD_ID_SGreen:
                       case GAD_ID_SBlue:
                       case GAD_ID_ERed:
                       case GAD_ID_EGreen:
                       case GAD_ID_EBlue:
                            RedrawGradient();
                            break;
                     }
                     break;
 
                /* Fenster-Schlieflsymbol auswerten */
                case WMHI_CLOSEWINDOW:
                     laufen = FALSE;
                     break;
              }
            }
 
            /* CTRL-C von der Shell erhalten ? */
            if(sigs & SIGBREAKF_CTRL_C) laufen = FALSE;
          }
 
          /* Fenster schlieflen */
          RA_CloseWindow(gb_WindowObj);
        }
      }
    }
    }
    }
    }
    }
    }
    }
 
    /* der IDCMP-Sender h‰ngt nicht in der Gadgetliste und mufl */
    /* deshalb extra freigegeben werden */    
    if(gb_Model) IIntuition->DisposeObject(gb_Model); 
 
    /* Window-Object freigeben, entsorgt auch Layout und Gadget-Objekte */
    IIntuition->DisposeObject(gb_WindowObj);
  }
 
  return 0;
}
AF106 GradientPrg-grab.png

New functions in the intuition.library V50-52

Open and close BOOPSI classes:

struct ClassLibrary *OpenClass( STRPTR name, ULONG version, Class **clasr );
VOID CloseClass( struct ClassLibrary *cl );

Internal help functions for BOOPSI objects:

VOID DoRender( Object *o, struct GadgetInfo *gi, ULONG flags );

Conducting a BOOPSI method (BOOPSI internal):

ULONG ICoerceMethodA( Class *cl, Object *obj, Msg msg );

Conducting a Super method (BOOPSI internal):

ULONG IDoSuperMethodA( Class *cl, Object *obj, Msg msg );

Conducting a Set method (BOOPSI internal):

ULONG ISetSuperAttrsA( Class *cl, Object *obj, struct TagItem *taglist );

Locking a screen (BOOPSI internal):

struct RastPort *LockScreenGI( struct GadgetInfo *gi, ULONG micros );
VOID UnlockScreenGI( struct GadgetInfo *gi, struct RastPort *rastport );

Monitoring a screen for changes

APTR StartScreenNotifyTagList( struct TagItem *taglist );
BOOL EndScreenNotify( APTR screen );

Determining the absolute position and size of a gadget:

ULONG GadgetBox( struct Gadget *gad, APTR domain, ULONG type, ULONG flags, APTR box);

Determining the attributes of a Boopsi gadget:

ULONG GetAttrsA (Object *object, struct TagItem *taglist);

Determining/setting the screen attributes:

LONG GetScreenAttr( struct Screen *scr, ULONG attr, LONG data, LONG size );
LONG SetScreenAttr( struct Screen *scr, ULONG attr, LONG data, LONG size );

Determining/setting the window attributes:

LONG GetWindowAttr( struct Window *win, ULONG attr, LONG data, LONG size );
LONG SetWindowAttr( struct Window *win, ULONG attr, LONG data, LONG size );

Showing/hiding the window:

BOOL ShowWindow( struct Window *win, struct Window *other );
BOOL HideWindow( struct Window *win );

Conducting a BOOPSI method:

ULONG IDoMethodA( Object *obj, Msg msg );

Locking a screen (instead of LockLayers):

BOOL LockScreen( struct Screen *scr, ULONG micros );
VOID UnlockScreen( struct Screen * scr );

Locking the screen list for changes:

struct Screen *LockScreenList( VOID );
VOID UnlockScreenList( VOID );

Determining the FillHook for the background:

struct Hook *ObtainIBackFill( struct DrawInfo *di, ULONG element, ULONG state, ULONG flags );
VOID ReleaseIBackFill( struct Hook *hook );

Setting attributes for a Boopsi gadget and possibly refreshing the display:

VOID RefreshSetGadgetAttrsA( struct Gadget *gad, struct Window *win, struct Requester *req, struct TagItem *taglist );

Removing all messages from the messageport for a defined window:

VOID StripIntuiMessages( struct MsgPort *msgport, struct Window *win );

Hook for filling free areas when scrolling:

VOID DoScrollHook(struct ScrollHook *scroll_hook, LONG scroll_mode);

Requesting i.e. setting an area in the RastPort, in which you can draw:

ULONG GetRenderDomain( struct RastPort *rp, struct Rectangle *rect );
ULONG SetRenderDomain( struct RastPort *rp, struct Rectangle *rect );

Drawing a colour gradient:

ULONG DrawGradient( struct RastPort * rp, LONG left, LONG top, LONG width, LONG height, struct IBox * domain, ULONG reserved, struct GradientSpec * gradientspec, struct DrawInfo * dri );
ULONG DirectionVector( ULONG degrees );

Authors

Written by Michael Christoph and Bernd Schmidt
Copyright (c) 2013 Michael Christoph