[Contents] [Index] [Help] [Retrace] [Browse <] [Browse >]

;/*
sc DATA=NEAR NMINC STRMERGE NOSTKCHK SAVEDS IGNORE=73 relative
slink FROM LIB:c.o relative.o TO relative LIB LIB:sc.lib LIB:amiga.lib
quit
*/

/* (c)  Copyright 1993-1999 Amiga, Inc.   All rights reserved. */
/* The information contained herein is subject to change without    */
/* notice, and is provided "as is" without warranty of any kind,    */
/* either expressed or implied.  The entire risk as to the use of   */
/* this information is assumed by the user.                         */

/*
 * relative.c - shows custom gadget relativity
 *
 * custom gadget relativity allows a gadget to arbitrarily resize
 * itself whenever the window changes size.  This is a complete superset
 * of the functionality of the old GRELWIDTH, GRELRIGHT, etc., features.
 * This example shows a subclass of gadgetclass whose imagery comes
 * from frameiclass.  This gadget's property is that it is always half
 * the size of its domain, and centered within it.  That is, it's always
 * half as wide and half as tall as the inner area of its window, and
 * centered within that area.
 */


#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <intuition/imageclass.h>
#include <intuition/cghooks.h>
#include <intuition/classes.h>
#include <intuition/classusr.h>

#include <clib/alib_protos.h>
#include <clib/alib_stdio_protos.h>
#include <clib/exec_protos.h>
#include <clib/graphics_protos.h>
#include <clib/intuition_protos.h>

struct Library *GfxBase = NULL;
struct Library *IntuitionBase = NULL;
struct Window *win = NULL;
struct Gadget *gad = NULL;
Class *customrelclass = NULL;

Class *initCustomRelClass(void);
ULONG __saveds __asm dispatchCustomRel( register __a0 Class *cl,
                                         register __a2 Object *o,
                                         register __a1 Msg msg );
void                 renderCustomRel( struct Gadget *gad,
                                       struct RastPort *rp,
                                       struct GadgetInfo *gi );
void                 layoutCustomRel( struct Gadget *gad,
                                       struct GadgetInfo *gi,
                                       ULONG initial );
LONG                 handleCustomRel( struct Gadget *gad,
                                       struct gpInput *msg );

void main(void)
{
  if ( GfxBase = OpenLibrary("graphics.library",39) )
  {
    if ( IntuitionBase = OpenLibrary("intuition.library",39) )
    {
      if ( customrelclass = initCustomRelClass() )
      {
        if ( gad = NewObject( customrelclass, NULL,
            GA_Left, 20,
            GA_Top, 20,
            GA_Width, 20,
            GA_Height, 20,
            GA_RelVerify, TRUE,
            GA_Immediate, TRUE,
            TAG_DONE ) )
        {
          if ( win = OpenWindowTags( NULL,
              WA_Title, "Custom Relativity Demo",
              WA_CloseGadget, TRUE,
              WA_DepthGadget, TRUE,
              WA_DragBar, TRUE,
              WA_SizeGadget, TRUE,
              WA_Gadgets, gad,
              WA_Activate, TRUE,
              WA_IDCMP, IDCMP_GADGETHELP | IDCMP_RAWKEY | IDCMP_CLOSEWINDOW |
                        IDCMP_GADGETDOWN | IDCMP_GADGETUP,
              WA_Width, 150,
              WA_Height, 150,
              WA_MinWidth, 50,
              WA_MinHeight, 50,
              WA_MaxWidth, ~0,
              WA_MaxHeight, ~0,
              WA_NoCareRefresh, TRUE,
              TAG_DONE ) )
          {
            BOOL terminated = FALSE;
            struct IntuiMessage *imsg;

            /* Turn on Gadget Help */
            HelpControl( win, HC_GADGETHELP );

            while (!terminated)
            {
              Wait (1 << win->UserPort->mp_SigBit);
              while (imsg = (struct IntuiMessage *) GetMsg(win->UserPort))
              {
                switch ( imsg->Class )
                {
                case IDCMP_CLOSEWINDOW:
                  terminated = TRUE;
                  break;

                case IDCMP_RAWKEY:
                  printf("RAWKEY %lx\n", imsg->Code);
                  break;

                case IDCMP_GADGETUP:
                  printf("Gadget Up\n");
                  break;

                case IDCMP_GADGETDOWN:
                  printf("Gadget Down\n");
                  break;

                case IDCMP_GADGETHELP:
                  if ( imsg->IAddress == NULL )
                  {
                    printf("Gadget Help: Mouse not over window\n");
                  }
                  else if ( imsg->IAddress == (APTR) win )
                  {
                    printf("Gadget Help: Mouse in window, not over a gadget\n");
                  }
                  else
                  {
                    /* Detect system gadgets.  Figure out by looking at
                     * system-gadget-type bits in GadgetType field:
                     */
                    LONG sysgtype =
                      ((struct Gadget *)imsg->IAddress)->GadgetType & GTYP_SYSTYPEMASK;
                    switch ( sysgtype )
                    {
                    case GTYP_SIZING:
                      printf("Gadget Help for window sizing gadget\n");
                      break;

                    case GTYP_WDRAGGING:
                      printf("Gadget Help for window drag-bar\n");
                      break;

                    case GTYP_WUPFRONT:
                      printf("Gadget Help for window depth gadget\n");
                      break;

                    case GTYP_WDOWNBACK:
                      printf("Gadget Help for window zoom gadget\n");
                      break;

                    case GTYP_CLOSE:
                      printf("Gadget Help for window close gadget\n");
                      break;

                    case 0:
                      /* In this example, we only have one gadget,
                       * so we know which one it is.  Normally, you'd
                       * have to figure that out here, using the
                       * usual techniques you already use for other
                       * gadget messages.
                       */
                      printf("Gadget Help for gadget, code 0x%x\n",
                          imsg->Code);
                      break;

                    default:
                      printf("Gadget Help on some other system gadget\n");
                      break;
                    }
                  }
                }
                ReplyMsg((struct Message *)imsg);
              }
            }
            CloseWindow( win );
          }
          DisposeObject( gad );
        }
        FreeClass( customrelclass );
      }
      CloseLibrary( IntuitionBase );
    }
    CloseLibrary( GfxBase );
  }
}


/* initCustomRelClass()
 *
 * Initialize a simple private subclass of gadgetclass that
 * knows about GM_LAYOUT.
 *
 */

Class *initCustomRelClass( void )
{
  Class *cl;

  /* Create a private class: */
  if ( cl = MakeClass( NULL, "gadgetclass", NULL, 0, 0 ) )
  {
    cl->cl_Dispatcher.h_SubEntry = NULL;
    cl->cl_Dispatcher.h_Entry = dispatchCustomRel;
    cl->cl_Dispatcher.h_Data = NULL;
  }
  return ( cl );
}

/* dispatchCustomRel()
 *
 * boopsi dispatcher for the custom relativity class.
 *
 */

ULONG __saveds __asm
dispatchCustomRel( register __a0 Class *cl,
                    register __a2 Object *o,
                    register __a1 Msg msg )
{
  ULONG retval = 1;
  Object *newobj;

  switch ( msg->MethodID )
  {
  case OM_NEW:
    if ( retval = (ULONG)(newobj = (Object *) DoSuperMethodA( cl, o, msg )) )
    {
      /* Set custom relativity */
      ((struct Gadget *)newobj)->Flags |= GFLG_RELSPECIAL;

      /* Tell Intuition this gadget supports gadget help */
      SetAttrs(newobj, GA_GadgetHelp, TRUE, TAG_DONE, NULL);

      /* Attempt to allocate a frame.  If I can't, then
       * delete myself and fail.
       */
      if ( ! ( ((struct Gadget *)newobj)->GadgetRender =
          NewObject( NULL, "frameiclass",
                     IA_FrameType, FRAME_BUTTON,
                     TAG_DONE ) ) )
      {
        CoerceMethod( cl, o, OM_DISPOSE );
        retval = NULL;
      }
    }
    break;

  case GM_LAYOUT:
    layoutCustomRel( (struct Gadget *)o, ((struct gpLayout *)msg)->gpl_GInfo,
        ((struct gpLayout *)msg)->gpl_Initial );
    break;

  case GM_RENDER:
    renderCustomRel( (struct Gadget *)o, ((struct gpRender *) msg)->gpr_RPort,
        ((struct gpRender *) msg)->gpr_GInfo );
    break;

  case GM_GOACTIVE:
    return( GMR_MEACTIVE );
    break;

  case GM_HELPTEST:
    return(GMR_HELPCODE | 0x0000C0DE);
    break;

  case GM_HANDLEINPUT:
    retval = handleCustomRel( (struct Gadget *)o, (struct gpInput *)msg );
    break;

  case OM_DISPOSE:
    DisposeObject( ((struct Gadget *)o)->GadgetRender );
    /* fall through to default */
  default:
    retval = (ULONG) DoSuperMethodA( cl, o, msg );
  }
  return( retval );
}


/* renderCustomRel()
 *
 * Simple routine to draw my imagery based on my selected state.
 *
 */
void
renderCustomRel( struct Gadget *gad, struct RastPort *rp, struct GadgetInfo *gi )
{
  DrawImageState( rp, gad->GadgetRender, gad->LeftEdge, gad->TopEdge,
      (gad->Flags & GFLG_SELECTED) ? IDS_SELECTED : IDS_NORMAL,
      gi ? gi->gi_DrInfo : NULL );
}


/* layoutCustomRel()
 *
 * Lay myself out based on my domain dimensions.  Refigure my own size,
 * then inform my image of the size change.
 *
 */
void
layoutCustomRel( struct Gadget *gad, struct GadgetInfo *gi, ULONG initial )
{
  if ( gi->gi_Requester )
  {
    /* Center it within the requester */
    gad->Width = gi->gi_Domain.Width / 2;
    gad->Height = gi->gi_Domain.Height / 2;
    gad->LeftEdge = gad->Width / 2;
    gad->TopEdge = gad->Height / 2;
  }
  else
  {
    /* Center it within the window, after accounting for
     * the window borders
     */
    gad->Width = ( gi->gi_Domain.Width -
        gi->gi_Window->BorderLeft - gi->gi_Window->BorderRight ) / 2;
    gad->Height = ( gi->gi_Domain.Height -
        gi->gi_Window->BorderTop - gi->gi_Window->BorderBottom ) / 2;
    gad->LeftEdge = ( gad->Width / 2 ) + gi->gi_Window->BorderLeft;
    gad->TopEdge = ( gad->Height / 2 ) + gi->gi_Window->BorderTop;
  }
  SetAttrs( gad->GadgetRender,
    IA_Width, gad->Width,
    IA_Height, gad->Height,
    TAG_DONE );
}


/* handleCustomRel()
 *
 * Routine to handle input to the gadget.  Behaves like a basic
 * hit-select gadget.
 *
 */
LONG
handleCustomRel( struct Gadget *gad, struct gpInput *msg )
{
  WORD selected = 0;
  struct RastPort *rp;
  LONG retval = GMR_MEACTIVE;

  /* Could send IM_HITTEST to image instead */
  if ( ( msg->gpi_Mouse.X >= 0 ) &&
      ( msg->gpi_Mouse.X < gad->Width ) &&
      ( msg->gpi_Mouse.Y >= 0 ) &&
      ( msg->gpi_Mouse.Y < gad->Height ) )
  {
    selected = GFLG_SELECTED;
  }

  if ((msg->gpi_IEvent->ie_Class == IECLASS_RAWMOUSE) &&
      (msg->gpi_IEvent->ie_Code == SELECTUP))
  {
    /* gadgetup, time to go */
    if ( selected )
    {
      retval = GMR_NOREUSE | GMR_VERIFY;
    }
    else
    {
      retval = GMR_NOREUSE;
    }
    /* and unselect the gadget on our way out... */
    selected = 0;
  }

  if ( ( gad->Flags & GFLG_SELECTED ) != selected )
  {
    gad->Flags ^= GFLG_SELECTED;
    if ( rp = ObtainGIRPort( msg->gpi_GInfo ) )
    {
      DoMethod( (Object *)gad, GM_RENDER, msg->gpi_GInfo, rp, GREDRAW_UPDATE );
      ReleaseGIRPort( rp );
    }
  }

  return( retval );
}