Copyright (c) Hyperion Entertainment and contributors.
Difference between revisions of "BOOPSI Images"
Steven Solie (talk | contribs) |
m (→mytextlabelclass.c: Removed some useless definitions. Some cleaning and type castings) |
||
(6 intermediate revisions by one other user not shown) | |||
Line 232: | Line 232: | ||
This method is not supported by the mytextlabelclass example. It passes this message to its superclass which does not support this method either. When the message returns from the superclass, the return value will be zero, indicating to the application that this method is not supported. |
This method is not supported by the mytextlabelclass example. It passes this message to its superclass which does not support this method either. When the message returns from the superclass, the return value will be zero, indicating to the application that this method is not supported. |
||
− | == |
+ | == Examples == |
+ | |||
+ | === usemyIC.c === |
||
+ | |||
+ | The example code initializes and uses a custom imageclass object. Notice that usemyIC.c directly manipulates fields within the Image structure embedded within the BOOPSI imageclass object. This is legal for image classes whose immediate superclass is imageclass (for the LeftEdge, TopEdge, Width, Height, ImageData, PlanePick, and PlaneOnOff Image structure fields only; the other Image structure fields are off limits). Indirect subclasses of imageclass may not alter the values in the embedded Image structure as future direct subclasses of imageclass may need to know about changes to values in the Image structure. |
||
+ | |||
+ | <syntaxhighlight> |
||
+ | /* |
||
+ | * usemyIC.c |
||
+ | * |
||
+ | * Originally written by David N. Junod |
||
+ | */ |
||
+ | |||
+ | #include <exec/types.h> |
||
+ | #include <exec/libraries.h> |
||
+ | #include <intuition/intuition.h> |
||
+ | #include <intuition/classes.h> |
||
+ | #include <intuition/classusr.h> |
||
+ | #include <intuition/cghooks.h> |
||
+ | #include <intuition/gadgetclass.h> |
||
+ | #include <intuition/imageclass.h> |
||
+ | #include <graphics/gfx.h> |
||
+ | #include <graphics/gfxmacros.h> |
||
+ | #include <libraries/gadtools.h> |
||
+ | #include <utility/tagitem.h> |
||
+ | |||
+ | #include <proto/exec.h> |
||
+ | #include <proto/dos.h> |
||
+ | #include <proto/intuition.h> |
||
+ | #include <proto/graphics.h> |
||
+ | #include <proto/utility.h> |
||
+ | #include <string.h> |
||
+ | |||
+ | struct IntuitionIFace *IIntuition = NULL; |
||
+ | |||
+ | Class *initmyTextLabelClass(VOID); |
||
+ | ULONG freemyTextLabelClass(Class * cl); |
||
+ | |||
+ | int main() |
||
+ | { |
||
+ | Class *cl; |
||
+ | struct Image *im; |
||
+ | struct Window *win; |
||
+ | |||
+ | struct Library *IntuitionBase = IExec->OpenLibrary("intuition.library", 50); |
||
+ | struct Library *GfxBase = IExec->OpenLibrary("graphics.library", 50); |
||
+ | |||
+ | IIntuition = (struct IntuitionIFace*)IExec->GetInterface(IntuitionBase, "main", 1, NULL); |
||
+ | IGraphics = (struct GraphicsIFace*)IExec->GetInterface(GfxBase, "main", 1, NULL); |
||
+ | |||
+ | if (IIntuition != NULL && IGraphics != NULL) |
||
+ | { |
||
+ | /* Open a window, without system gadgets or IDCMP events */ |
||
+ | if (win = IIntuition->OpenWindowTags(NULL, |
||
+ | WA_Left, 10, |
||
+ | WA_Top, 10, |
||
+ | WA_Width, 320, |
||
+ | WA_Height, 100, |
||
+ | TAG_END)) |
||
+ | { |
||
+ | /* Cache the pointer to the RastPort */ |
||
+ | struct RastPort *rp = win->RPort; |
||
+ | |||
+ | /* Cache the upper-left coordinates of the window */ |
||
+ | uint16 top = win->BorderTop + INTERHEIGHT; |
||
+ | uint16 left = win->BorderRight + INTERWIDTH; |
||
+ | |||
+ | /* Cache the height of the font */ |
||
+ | uint16 height = rp->TxHeight + INTERHEIGHT; |
||
+ | |||
+ | /* Initialize the custom image class. */ |
||
+ | if (cl = initmyTextLabelClass()) |
||
+ | { |
||
+ | /* Create a new image structure, using the given string. */ |
||
+ | if (im = IIntuition->NewObject(cl, NULL, |
||
+ | IA_Data, (ULONG) "Line _1", |
||
+ | TAG_END)) |
||
+ | { |
||
+ | /* Paint using the provided text string. */ |
||
+ | IIntuition->DrawImageState(rp, im, left, top, |
||
+ | IDS_NORMAL, NULL); |
||
+ | |||
+ | /* Replace the text string, and paint it. */ |
||
+ | im->ImageData = (USHORT *) "Line _2"; |
||
+ | IIntuition->DrawImageState(rp, im, left, top + height, |
||
+ | IDS_NORMAL, NULL); |
||
+ | |||
+ | /* Replace the text string, and paint it. */ |
||
+ | im->ImageData = (USHORT *) "Line _3"; |
||
+ | IIntuition->DrawImageState(rp, im, left, top + (height * 2), |
||
+ | IDS_NORMAL, NULL); |
||
+ | |||
+ | /* Free the image. */ |
||
+ | IIntuition->DisposeObject(im); |
||
+ | } |
||
+ | |||
+ | /* Free the image class. */ |
||
+ | freemyTextLabelClass(cl); |
||
+ | } |
||
+ | |||
+ | IDOS->Delay(250); |
||
+ | IIntuition->CloseWindow(win); |
||
+ | } |
||
+ | } |
||
+ | |||
+ | IExec->DropInterface((struct Interface*)IGraphics); |
||
+ | IExec->DropInterface((struct Interface*)IIntuition); |
||
+ | IExec->CloseLibrary(GfxBase); |
||
+ | IExec->CloseLibrary(IntuitionBase); |
||
+ | |||
+ | return 0; |
||
+ | } |
||
+ | </syntaxhighlight> |
||
+ | |||
+ | === mytextlabelclass.c === |
||
+ | |||
+ | The image class example code, mytextlabelclass.c, illustrates a complete custom image class. This image class provides an application with textual labels that have a particular character underlined. This is useful for indicating which key controls a gadget (although the example provided only utilizes imageclass objects; there are no gadgets involved). |
||
+ | |||
+ | A custom image can be used in the place of any standard Intuition Image structure. For example, an application can attach an imageclass object to: the GadgetRender and SelectRender fields of a Gadget structure (defined in <intuition/intuition.h>), the ReqImage field of a Requester structure, or even the ItemFill field of the MenuItem structure. |
||
<syntaxhighlight> |
<syntaxhighlight> |
||
Line 242: | Line 360: | ||
* struct Image { |
* struct Image { |
||
* |
* |
||
− | * |
+ | * int16 LeftEdge; <----Offset relative to the container |
− | * |
+ | * int16 TopEdge; |
* |
* |
||
− | * |
+ | * int16 Width; <----Contains the text extent of the string |
− | * |
+ | * int16 Height; |
* |
* |
||
− | * |
+ | * int16 Depth; <----Maintained by BOOPSI (must be set to CUSTOMIMAGEDEPTH). |
* |
* |
||
− | * |
+ | * Uint16 *ImageData; <----Pointer to a NULL terminated text string |
* |
* |
||
− | * |
+ | * uint8 PlanePick; <----We use this for the foreground color |
* |
* |
||
− | * |
+ | * uint8 PlaneOnOff; <----We use this for the background color |
* |
* |
||
* struct Image *NextImage; <----Pointer to the next image. Handled by DrawImage(). }; |
* struct Image *NextImage; <----Pointer to the next image. Handled by DrawImage(). }; |
||
Line 280: | Line 398: | ||
#include <proto/utility.h> |
#include <proto/utility.h> |
||
− | extern struct |
+ | extern struct IntuitionIFace *IIntuition; |
+ | extern struct GraphicsIFace *IGraphics; |
||
/* |
/* |
||
Line 286: | Line 405: | ||
* object is an intuition Image structure. |
* object is an intuition Image structure. |
||
*/ |
*/ |
||
− | #define IM(o) |
+ | #define IM(o) ((struct Image *)(o)) |
− | #define MYCLASSID |
+ | #define MYCLASSID NULL |
− | #define SUPERCLASSID |
+ | #define SUPERCLASSID (IMAGECLASS) |
Class *initmyTextLabelClass(VOID); |
Class *initmyTextLabelClass(VOID); |
||
− | + | uint32 freemyTextLabelClass(Class * cl); |
|
− | + | uint32 dispatchmyTextLabel(Class * cl, Object * o, Msg msg); |
|
− | + | uint32 setmyTextLabelAttrs(Class * cl, Object * o, struct opSet * msg); |
|
− | + | uint32 getmyTextLabelAttr(Class * cl, Object * o, struct opGet * msg); |
|
− | + | uint32 drawmyTextLabel(Class * cl, Object * o, struct impDraw * msg); |
|
− | + | int16 aTextExtent(struct RastPort *, STRPTR, LONG, struct TextExtent *); |
|
− | + | uint16 GetLabelKeystroke(STRPTR label); |
|
static VOID getContentsExtent(Class * cl, Object * o, struct DrawInfo * drinfo); |
static VOID getContentsExtent(Class * cl, Object * o, struct DrawInfo * drinfo); |
||
− | |||
− | /* prototypes of functions from classface.o */ |
||
− | ULONG DoMethod(Object * o, ULONG methodID,...); |
||
− | ULONG DoSuperMethod(Class * cl, Object * o, ULONG methodID,...); |
||
− | ULONG CoerceMethod(Class * cl, Object * o, ULONG methodID,...); |
||
− | ULONG CM(Class * cl, Object * o, Msg msg); |
||
− | ULONG DM(Object * o, Msg msg); |
||
− | ULONG DSM(Class * cl, Object * o, Msg msg); |
||
− | ULONG SetSuperAttrs(Class * cl, Object * o, ULONG data,...); |
||
struct localObjData |
struct localObjData |
||
Line 316: | Line 426: | ||
/* The key that is underlined */ |
/* The key that is underlined */ |
||
− | + | uint16 lod_Key; |
|
/* DrawMode */ |
/* DrawMode */ |
||
− | + | uint8 lod_Mode; |
|
}; |
}; |
||
Line 327: | Line 437: | ||
Class *cl; |
Class *cl; |
||
− | if (cl = IIntuition->MakeClass(MYCLASSID, |
+ | if ((cl = IIntuition->MakeClass(MYCLASSID, |
− | + | SUPERCLASSID, NULL, |
|
− | + | sizeof(struct localObjData), 0))) |
|
{ |
{ |
||
/* Fill in the callback hook */ |
/* Fill in the callback hook */ |
||
− | cl->cl_Dispatcher.h_Entry = dispatchmyTextLabel; |
+ | cl->cl_Dispatcher.h_Entry = (HOOKFUNC)dispatchmyTextLabel; |
} |
} |
||
/* Return a pointer to the class */ |
/* Return a pointer to the class */ |
||
Line 339: | Line 449: | ||
− | + | uint32 freemyTextLabelClass(Class * cl) |
|
{ |
{ |
||
− | |||
/* Try to free the public class */ |
/* Try to free the public class */ |
||
− | return (( |
+ | return ((uint32) IIntuition->FreeClass(cl)); |
} |
} |
||
− | + | uint32 dispatchmyTextLabel(Class * cl, Object * o, Msg msg) |
|
{ |
{ |
||
struct localObjData *lod; |
struct localObjData *lod; |
||
Object *newobj; |
Object *newobj; |
||
− | + | uint32 retval; |
|
switch (msg->MethodID) |
switch (msg->MethodID) |
||
{ |
{ |
||
− | case OM_NEW: |
+ | case OM_NEW: |
− | /* Pass up to the superclass... */ |
+ | /* Pass up to the superclass... */ |
− | if (newobj = (Object *) |
+ | if ((newobj = (Object *) IIntuition->IDoSuperMethodA(cl, o, msg))) |
− | { |
+ | { |
− | struct TagItem *attrs = ((struct opSet *) msg)->ops_AttrList; |
+ | struct TagItem *attrs = ((struct opSet *) msg)->ops_AttrList; |
− | struct DrawInfo *drinfo; |
+ | struct DrawInfo *drinfo; |
− | /* Get the DrawInfo */ |
+ | /* Get the DrawInfo */ |
− | drinfo = (struct DrawInfo *) IUtility->GetTagData(SYSIA_DrawInfo, NULL, attrs); |
+ | drinfo = (struct DrawInfo *) IUtility->GetTagData(SYSIA_DrawInfo, NULL, attrs); |
− | /* Get the instance data */ |
+ | /* Get the instance data */ |
− | lod = INST_DATA(cl, newobj); |
+ | lod = (struct localObjData *)INST_DATA(cl, newobj); |
− | /* Establish defaults */ |
+ | /* Establish defaults */ |
− | IM(newobj)->PlanePick = 1; |
+ | IM(newobj)->PlanePick = 1; |
− | lod->lod_Mode = JAM1; |
+ | lod->lod_Mode = JAM1; |
− | /* Set the attributes */ |
+ | /* Set the attributes */ |
− | setmyTextLabelAttrs(cl, newobj, (struct opSet *) msg); |
+ | setmyTextLabelAttrs(cl, newobj, (struct opSet *) msg); |
− | /* Get the bounding rectangle of the label */ |
+ | /* Get the bounding rectangle of the label */ |
− | getContentsExtent(cl, newobj, drinfo); |
+ | getContentsExtent(cl, newobj, drinfo); |
− | } |
+ | } |
− | retval = ( |
+ | retval = (uint32) newobj; |
− | break; |
+ | break; |
− | case OM_GET: |
+ | case OM_GET: |
− | retval = getmyTextLabelAttr(cl, o, (struct opGet *) msg); |
+ | retval = getmyTextLabelAttr(cl, o, (struct opGet *) msg); |
− | break; |
+ | break; |
− | case OM_UPDATE: |
+ | case OM_UPDATE: |
− | case OM_SET: |
+ | case OM_SET: |
− | /* Do the superclass first */ |
+ | /* Do the superclass first */ |
− | retval = |
+ | retval = IIntuition->IDoSuperMethodA(cl, o, msg); |
− | /* Call our set routines */ |
+ | /* Call our set routines */ |
− | retval += setmyTextLabelAttrs(cl, o, (struct opSet *) msg); |
+ | retval += setmyTextLabelAttrs(cl, o, (struct opSet *) msg); |
− | break; |
+ | break; |
− | case IM_DRAW: /* draw the label */ |
+ | case IM_DRAW: /* draw the label */ |
− | case IM_DRAWFRAME: /* drawmyTextLabel() will take care of |
+ | case IM_DRAWFRAME: /* drawmyTextLabel() will take care of extra framing info */ |
+ | retval = drawmyTextLabel(cl, o, (struct impDraw *) msg); |
||
− | extra framing info */ |
||
− | + | break; |
|
− | break; |
||
− | /* Let the superclass handle everything else */ |
+ | /* Let the superclass handle everything else */ |
− | default: |
+ | default: |
− | retval = ( |
+ | retval = (uint32) IIntuition->IDoSuperMethodA(cl, o, msg); |
− | break; |
+ | break; |
} |
} |
||
Line 411: | Line 519: | ||
/* Set attributes of an object */ |
/* Set attributes of an object */ |
||
− | + | uint32 setmyTextLabelAttrs(Class * cl, Object * o, struct opSet * msg) |
|
{ |
{ |
||
− | struct localObjData *lod = INST_DATA(cl, o); |
+ | struct localObjData *lod = (struct localObjData *)INST_DATA(cl, o); |
struct TagItem *tags = msg->ops_AttrList; |
struct TagItem *tags = msg->ops_AttrList; |
||
struct TagItem *tstate; |
struct TagItem *tstate; |
||
struct TagItem *tag; |
struct TagItem *tag; |
||
− | + | uint32 tidata; |
|
/* process rest */ |
/* process rest */ |
||
tstate = tags; |
tstate = tags; |
||
− | while (tag = NextTagItem(&tstate)) |
+ | while ((tag = IUtility->NextTagItem(&tstate))) |
{ |
{ |
||
tidata = tag->ti_Data; |
tidata = tag->ti_Data; |
||
Line 427: | Line 535: | ||
{ |
{ |
||
case IA_FGPen: |
case IA_FGPen: |
||
− | IM(o)->PlanePick = ( |
+ | IM(o)->PlanePick = (uint8) tidata; |
break; |
break; |
||
case IA_BGPen: |
case IA_BGPen: |
||
− | IM(o)->PlaneOnOff = ( |
+ | IM(o)->PlaneOnOff = (uint8) tidata; |
break; |
break; |
||
− | + | /* Must be a TextFont pointer. */ |
|
case IA_Font: |
case IA_Font: |
||
− | + | /* Set the font */ |
|
lod->lod_Font = (struct TextFont *) tidata; |
lod->lod_Font = (struct TextFont *) tidata; |
||
break; |
break; |
||
− | + | /* Drawing mode to use */ |
|
case IA_Mode: |
case IA_Mode: |
||
− | lod->lod_Mode = ( |
+ | lod->lod_Mode = (uint8) tidata; |
break; |
break; |
||
case IA_Data: |
case IA_Data: |
||
− | IM(o)->ImageData = ( |
+ | IM(o)->ImageData = (uint16 *) tidata; |
lod->lod_Key = GetLabelKeystroke((STRPTR) tidata); |
lod->lod_Key = GetLabelKeystroke((STRPTR) tidata); |
||
break; |
break; |
||
Line 457: | Line 565: | ||
/* Inquire attributes of an object */ |
/* Inquire attributes of an object */ |
||
− | + | uint32 getmyTextLabelAttr(Class * cl, Object * o, struct opGet * msg) |
|
{ |
{ |
||
− | struct localObjData *lod = INST_DATA(cl, o); |
+ | struct localObjData *lod = (struct localObjData *)INST_DATA(cl, o); |
switch (msg->opg_AttrID) |
switch (msg->opg_AttrID) |
||
{ |
{ |
||
− | case IA_Font: |
+ | case IA_Font: |
− | *msg->opg_Storage = ( |
+ | *msg->opg_Storage = (uint32) lod->lod_Font; |
− | break; |
+ | break; |
− | case IA_Mode: |
+ | case IA_Mode: |
− | *msg->opg_Storage = ( |
+ | *msg->opg_Storage = (uint32) lod->lod_Mode; |
− | break; |
+ | break; |
/* Let the superclass try */ |
/* Let the superclass try */ |
||
− | default: |
+ | default: |
− | return (( |
+ | return ((uint32) IIntuition->IDoSuperMethodA(cl, o, (Msg)msg)); |
} |
} |
||
Line 480: | Line 588: | ||
− | + | uint32 drawmyTextLabel(Class * cl, Object * o, struct impDraw * msg) |
|
{ |
{ |
||
− | struct localObjData *lod = INST_DATA(cl, o); |
+ | struct localObjData *lod = (struct localObjData *)INST_DATA(cl, o); |
STRPTR label = (STRPTR) IM(o)->ImageData; |
STRPTR label = (STRPTR) IM(o)->ImageData; |
||
struct DrawInfo *di = msg->imp_DrInfo; |
struct DrawInfo *di = msg->imp_DrInfo; |
||
struct RastPort *rp = msg->imp_RPort; |
struct RastPort *rp = msg->imp_RPort; |
||
struct TextFont *tf = NULL; |
struct TextFont *tf = NULL; |
||
− | + | int16 len = strlen(label); |
|
− | + | int16 left, top; |
|
− | + | int16 height = 0; |
|
− | + | int16 width = 0; |
|
− | + | int16 i; |
|
/* Clear the key */ |
/* Clear the key */ |
||
Line 539: | Line 647: | ||
if (label[i] == '_') |
if (label[i] == '_') |
||
{ |
{ |
||
− | + | int16 bot = (top + rp->TxHeight - rp->TxBaseline); |
|
− | + | int16 mark; |
|
/* Draw the first part of the string */ |
/* Draw the first part of the string */ |
||
Line 562: | Line 670: | ||
/* Return the underlined character */ |
/* Return the underlined character */ |
||
− | lod->lod_Key = ( |
+ | lod->lod_Key = (uint16) label[i]; |
} |
} |
||
} |
} |
||
Line 569: | Line 677: | ||
if (!lod->lod_Key) |
if (!lod->lod_Key) |
||
{ |
{ |
||
− | + | /* Didn't find an '_' sign */ |
|
− | Text(rp, label, len); |
+ | IGraphics->Text(rp, label, len); |
} |
} |
||
return (1L); |
return (1L); |
||
Line 576: | Line 684: | ||
− | + | uint16 GetLabelKeystroke(STRPTR label) |
|
{ |
{ |
||
LONG count = (label) ? strlen(label) : 0L; |
LONG count = (label) ? strlen(label) : 0L; |
||
Line 587: | Line 695: | ||
if (label[i] == '_') |
if (label[i] == '_') |
||
{ |
{ |
||
− | return (( |
+ | return ((uint16) label[(i + 1)]); |
} |
} |
||
} |
} |
||
Line 596: | Line 704: | ||
/* TextExtent that honors the '_' as being a non-printable character (once) */ |
/* TextExtent that honors the '_' as being a non-printable character (once) */ |
||
− | + | int16 aTextExtent(struct RastPort * rp, STRPTR string, LONG count, struct TextExtent * te) |
|
{ |
{ |
||
− | + | int16 retval = FALSE; |
|
STRPTR buffer; |
STRPTR buffer; |
||
LONG i; |
LONG i; |
||
/* Allocate a temporary buffer */ |
/* Allocate a temporary buffer */ |
||
− | if (buffer = IExec->AllocVecTags((count + 1), AVT_ClearWithValue, 0, TAG_END)) |
+ | if ((buffer = (STRPTR)IExec->AllocVecTags((count + 1), AVT_ClearWithValue, 0, TAG_END))) |
{ |
{ |
||
− | + | /* Step through string */ |
|
− | + | for (i = 0; i < count; i++) |
|
+ | { |
||
− | { |
||
/* Is this an '_' sign? */ |
/* Is this an '_' sign? */ |
||
if (string[i] == '_') |
if (string[i] == '_') |
||
{ |
{ |
||
− | + | /* Add the rest of the label to the buffer */ |
|
− | + | strcat (buffer, &string[(i + 1)]); |
|
− | + | /* Adjust the length of the string. */ |
|
− | + | count--; |
|
− | + | break; |
|
− | + | } |
|
− | + | else |
|
− | + | { |
|
− | + | /* Copy each character over, until we reach the _ mark */ |
|
− | + | buffer[i] = string[i]; |
|
− | + | } |
|
} |
} |
||
Line 628: | Line 736: | ||
IGraphics->TextExtent(rp, buffer, count, te); |
IGraphics->TextExtent(rp, buffer, count, te); |
||
− | + | /* Free the temporary buffer */ |
|
− | + | IExec->FreeVec (buffer); |
|
− | + | /* Show that we were successful */ |
|
− | + | retval = TRUE; |
|
} |
} |
||
Line 641: | Line 749: | ||
static VOID getContentsExtent(Class * cl, Object * o, struct DrawInfo * drinfo) |
static VOID getContentsExtent(Class * cl, Object * o, struct DrawInfo * drinfo) |
||
{ |
{ |
||
− | struct localObjData *lod = INST_DATA(cl, o); |
+ | struct localObjData *lod = (localObjData *)INST_DATA(cl, o); |
− | struct TextExtent te = { |
+ | struct TextExtent te = {0, 0, {0, 0, 0, 0}}; |
struct RastPort rp; |
struct RastPort rp; |
||
STRPTR label; |
STRPTR label; |
||
/* maybe look at some flags to handle other types of text someday */ |
/* maybe look at some flags to handle other types of text someday */ |
||
− | if (label = (STRPTR) IM(o)->ImageData) |
+ | if ((label = (STRPTR) IM(o)->ImageData)) |
{ |
{ |
||
/* Initialize the RastPort */ |
/* Initialize the RastPort */ |
Latest revision as of 13:10, 10 September 2024
Contents
Introduction
BOOPSI's imageclass is one of the standard classes built into Intuition. As its name implies, it is a class of Intuition Images. These BOOPSI images can be used in place of traditional Image structure (as they contain an Intuition Image structure), but they are much more powerful. By using BOOPSI methods, an application or Intuition can tell an imageclass object to render itself. Because it renders itself (rather than Intuition rendering it), the imageclass object is free to render whatever it wants (well, within reason). For example, a BOOPSI image object can render itself according to the current display resolution, or to scale itself to any size an application requests.
BOOPSI Image Methods
Imageclass defines several methods of its own which subclasses of imageclass either have to implement or pass on to their superclass. The method IDs for imageclass are defined in <intuition/imageclass.h>. Each method requires some parameters.
Method | Description |
---|---|
IM_DRAW | Draw image with state. |
IM_DRAWFRAME | Draw image within frame limits. |
IM_ERASE | Erase image with state. |
IM_ERASEFRAME | Erase image within frame. |
IM_HITFRAME | Determine if image was hit within frame. |
IM_HITTEST | Determine if image was hit. |
The following methods are described at the imageclass level although it's up to the subclasses to actually implement them. If a class does not implement these methods it should either return zero, indicating that this class does not support the method, or defer processing on to its superclass.
Method | Description |
---|---|
IM_FRAMEBOX | Get recommended frame around some box. |
IM_EXTENT | Inquire about rendering extent. |
IM_EXTENTFRAME | Inquire about rendering extent with dimensions. |
The formats of each of these BOOPSI messages all differ. The MethodID is the only parameter common to each method.
IM_DRAW
The IM_DRAW method is used to tell the image to render itself. The Intuition function DrawImageState() uses this method. IM_DRAW receives the following parameters:
struct impDraw { uint32 MethodID; struct RastPort *imp_RPort; struct { int16 X; int16 Y; } imp_Offset; uint32 imp_State; struct DrawInfo *imp_DrInfo; };
The imp_State field contains the visual state to render the image. The visual states (defined in <intuition/imageclass.h>) are:
IDS_NORMAL | idle state |
IDS_SELECTED | for selected gadgets. |
IDS_DISABLED | for disabled gadgets. |
IDS_BUSY | for future functionality |
IDS_INDETERMINATE | for future functionality |
IDS_INACTIVENORMAL | normal, in inactive window border. |
IDS_INACTIVESELECTED | selected, in inactive border. |
IDS_INACTIVEDISABLED | disabled, in inactive border. |
When setting the pens to render an image, use the values from the imp_DrInfo->dri_Pens pen array (Note that it is possible that imp_DrInfo will be NULL). The possible pen values are defined in <intuition/screens.h>.
The following code fragment shows how to use the shadow color for rendering.
uint16 *pens = (imp->imp_DrInfo) ? imp->imp_DrInfo->dri_Pens : NULL; if (pens) { IIntuition->SetAPen (imp->imp_RPort, pens[SHADOWPEN]); }
IM_DRAWFRAME
The IM_DRAWFRAME method instructs the image to render itself within the confines of the given rectangle. It receives the following parameters:
struct impDraw { uint32 MethodID; struct RastPort *imp_RPort; struct { int16 X; int16 Y; } imp_Offset; uint32 imp_State; struct DrawInfo *imp_DrInfo; struct { int16 Width; int16 Height; } imp_Dimensions; };
The Width and Height fields provide the object's rectangular bounds. How the image object deals with the frame is implementation specific. Typically, a scaleable image will scale itself as best it can to fit into the rectangle. The mytextlabelclass.c example does not actually implement this method, instead mytextlabelclass treats IM_DRAWFRAME like the IM_DRAW method.
In general, applications that use this method to draw an object should use the IM_ERASEFRAME method (see below) to erase it. This will ensure that the image was erased at the proper scale.
IM_ERASE
The IM_ERASE method tells an image to erase itself. The Intuition function EraseImage() uses this method. IM_ERASE receives the following parameters:
struct impErase { uint32 MethodID; struct RastPort *imp_RPort; struct { int16 X; int16 Y; } imp_Offset; };
The mytextlabelclass example doesn't know anything about this method, so it blindly passes this message on to the superclass. The superclass, imageclass, will call the graphics.library function EraseRect() using the dimensions found in the imageclass object's Image structure.
IM_ERASEFRAME
The IM_ERASEFRAME method instructs an image confined to a given rectangle to erase itself. Normally this method is used to erase an image drawn using the IM_DRAWFRAME method. This method expects the following parameters:
struct impEraseFrame { uint32 MethodID; struct RastPort *imp_RPort; struct { int16 X; int16 Y; } imp_Offset; /* these parameters only valid for IM_ERASEFRAME */ struct { int16 Width; int16 Height; } imp_Dimensions; };
The mytextlabelclass example blindly passes this method on to its superclass. The superclass treats IM_ERASEFRAME just like IM_ERASE.
IM_HITFRAME
The IM_HITFRAME method is used to determine if a point is within an image that is contained within (or scaled to) the given rectangle. This method is intended to test images that were rendered using IM_DRAWFRAME. This method receives the following parameters:
struct impHitFrame { uint32 MethodID; struct { int16 X; int16 Y; } imp_Point; struct { int16 Width; int16 Height; } imp_Dimensions; };
The mytextlabelclass example blindly passes this method on to its superclass. The superclass treat this meothd just like the IM_HITTEST method.
IM_HITTEST
IM_HITTEST returns true if a point is within the image. The Intuition function PointInImage() uses this method. IM_HITTEST requires the following parameters:
struct impHitTest { uint16 MethodID; struct { int16 X; int16 Y; } imp_Point; };
The mytextlabelclass example blindly passes this method on to its superclass. The superclass, imageclass, will return TRUE if the point is within the old Image structure box.
IM_FRAMEBOX
The IM_FRAMEBOX method returns size information for an image (usually some sort of frame image). The following parameters are associated with the IM_FRAMEBOX method.
struct impFrameBox { uint32 MethodID; struct IBox *imp_ContentsBox; /* Application supplied IBox for the result */ struct IBox *imp_FrameBox; /* Rectangle to frame */ struct DrawInfo *imp_DrInfo; uint32 imp_FrameFlags; };
This method is used to ask the image what size it would like to be, if it had to frame the rectangle in the imp_FrameBox field. This method normally applies only to image classes that put a frame around some object (like frameiclass). By passing the dimensions and position of a rectangle, the framing image determines the position and size it should be to properly "frame" the object bounded by the imp_FrameBox rectangle. IM_FRAMEBOX stores the result in the IBox structure pointed to by imp_ContentsBox. This method allows an application to use a framing image without having to worry about image specific details such as accounting for the thickness of the frame or centering the frame around the object.
The imp_FrameFlags field is a bit field used to specify certain options for the IM_FRAMEBOX method. Currently, there is only one defined for it, FRAMEF_SPECIFY. If this bit is set, IM_FRAMEBOX has to use the width and height supplied to it in the imp_FrameBox field (even if these are too small!) as the frame dimensions. It can only adjust its position, typically to center the object as best as possible.
This method is not supported by the mytextlabelclass example. It passes this message to its superclass which does not support this method either. When the message returns from the superclass, the return value will be zero, indicating to the application that this method is not supported.
Examples
usemyIC.c
The example code initializes and uses a custom imageclass object. Notice that usemyIC.c directly manipulates fields within the Image structure embedded within the BOOPSI imageclass object. This is legal for image classes whose immediate superclass is imageclass (for the LeftEdge, TopEdge, Width, Height, ImageData, PlanePick, and PlaneOnOff Image structure fields only; the other Image structure fields are off limits). Indirect subclasses of imageclass may not alter the values in the embedded Image structure as future direct subclasses of imageclass may need to know about changes to values in the Image structure.
/* * usemyIC.c * * Originally written by David N. Junod */ #include <exec/types.h> #include <exec/libraries.h> #include <intuition/intuition.h> #include <intuition/classes.h> #include <intuition/classusr.h> #include <intuition/cghooks.h> #include <intuition/gadgetclass.h> #include <intuition/imageclass.h> #include <graphics/gfx.h> #include <graphics/gfxmacros.h> #include <libraries/gadtools.h> #include <utility/tagitem.h> #include <proto/exec.h> #include <proto/dos.h> #include <proto/intuition.h> #include <proto/graphics.h> #include <proto/utility.h> #include <string.h> struct IntuitionIFace *IIntuition = NULL; Class *initmyTextLabelClass(VOID); ULONG freemyTextLabelClass(Class * cl); int main() { Class *cl; struct Image *im; struct Window *win; struct Library *IntuitionBase = IExec->OpenLibrary("intuition.library", 50); struct Library *GfxBase = IExec->OpenLibrary("graphics.library", 50); IIntuition = (struct IntuitionIFace*)IExec->GetInterface(IntuitionBase, "main", 1, NULL); IGraphics = (struct GraphicsIFace*)IExec->GetInterface(GfxBase, "main", 1, NULL); if (IIntuition != NULL && IGraphics != NULL) { /* Open a window, without system gadgets or IDCMP events */ if (win = IIntuition->OpenWindowTags(NULL, WA_Left, 10, WA_Top, 10, WA_Width, 320, WA_Height, 100, TAG_END)) { /* Cache the pointer to the RastPort */ struct RastPort *rp = win->RPort; /* Cache the upper-left coordinates of the window */ uint16 top = win->BorderTop + INTERHEIGHT; uint16 left = win->BorderRight + INTERWIDTH; /* Cache the height of the font */ uint16 height = rp->TxHeight + INTERHEIGHT; /* Initialize the custom image class. */ if (cl = initmyTextLabelClass()) { /* Create a new image structure, using the given string. */ if (im = IIntuition->NewObject(cl, NULL, IA_Data, (ULONG) "Line _1", TAG_END)) { /* Paint using the provided text string. */ IIntuition->DrawImageState(rp, im, left, top, IDS_NORMAL, NULL); /* Replace the text string, and paint it. */ im->ImageData = (USHORT *) "Line _2"; IIntuition->DrawImageState(rp, im, left, top + height, IDS_NORMAL, NULL); /* Replace the text string, and paint it. */ im->ImageData = (USHORT *) "Line _3"; IIntuition->DrawImageState(rp, im, left, top + (height * 2), IDS_NORMAL, NULL); /* Free the image. */ IIntuition->DisposeObject(im); } /* Free the image class. */ freemyTextLabelClass(cl); } IDOS->Delay(250); IIntuition->CloseWindow(win); } } IExec->DropInterface((struct Interface*)IGraphics); IExec->DropInterface((struct Interface*)IIntuition); IExec->CloseLibrary(GfxBase); IExec->CloseLibrary(IntuitionBase); return 0; }
mytextlabelclass.c
The image class example code, mytextlabelclass.c, illustrates a complete custom image class. This image class provides an application with textual labels that have a particular character underlined. This is useful for indicating which key controls a gadget (although the example provided only utilizes imageclass objects; there are no gadgets involved).
A custom image can be used in the place of any standard Intuition Image structure. For example, an application can attach an imageclass object to: the GadgetRender and SelectRender fields of a Gadget structure (defined in <intuition/intuition.h>), the ReqImage field of a Requester structure, or even the ItemFill field of the MenuItem structure.
/* * Original code written by David N. Junod * * The Image structure as used by this class: * * struct Image { * * int16 LeftEdge; <----Offset relative to the container * int16 TopEdge; * * int16 Width; <----Contains the text extent of the string * int16 Height; * * int16 Depth; <----Maintained by BOOPSI (must be set to CUSTOMIMAGEDEPTH). * * Uint16 *ImageData; <----Pointer to a NULL terminated text string * * uint8 PlanePick; <----We use this for the foreground color * * uint8 PlaneOnOff; <----We use this for the background color * * struct Image *NextImage; <----Pointer to the next image. Handled by DrawImage(). }; */ #include <exec/types.h> #include <exec/memory.h> #include <exec/libraries.h> #include <intuition/intuition.h> #include <intuition/classes.h> #include <intuition/classusr.h> #include <intuition/cghooks.h> #include <intuition/gadgetclass.h> #include <intuition/imageclass.h> #include <intuition/icclass.h> #include <intuition/screens.h> #include <graphics/gfx.h> #include <graphics/gfxmacros.h> #include <libraries/gadtools.h> #include <utility/tagitem.h> #include <proto/exec.h> #include <proto/intuition.h> #include <proto/graphics.h> #include <proto/utility.h> extern struct IntuitionIFace *IIntuition; extern struct GraphicsIFace *IGraphics; /* * Because we are dealing with imageclass objects, the data structure that makes up the * object is an intuition Image structure. */ #define IM(o) ((struct Image *)(o)) #define MYCLASSID NULL #define SUPERCLASSID (IMAGECLASS) Class *initmyTextLabelClass(VOID); uint32 freemyTextLabelClass(Class * cl); uint32 dispatchmyTextLabel(Class * cl, Object * o, Msg msg); uint32 setmyTextLabelAttrs(Class * cl, Object * o, struct opSet * msg); uint32 getmyTextLabelAttr(Class * cl, Object * o, struct opGet * msg); uint32 drawmyTextLabel(Class * cl, Object * o, struct impDraw * msg); int16 aTextExtent(struct RastPort *, STRPTR, LONG, struct TextExtent *); uint16 GetLabelKeystroke(STRPTR label); static VOID getContentsExtent(Class * cl, Object * o, struct DrawInfo * drinfo); struct localObjData { /* Font to use */ struct TextFont *lod_Font; /* The key that is underlined */ uint16 lod_Key; /* DrawMode */ uint8 lod_Mode; }; Class *initmyTextLabelClass(VOID) { Class *cl; if ((cl = IIntuition->MakeClass(MYCLASSID, SUPERCLASSID, NULL, sizeof(struct localObjData), 0))) { /* Fill in the callback hook */ cl->cl_Dispatcher.h_Entry = (HOOKFUNC)dispatchmyTextLabel; } /* Return a pointer to the class */ return (cl); } uint32 freemyTextLabelClass(Class * cl) { /* Try to free the public class */ return ((uint32) IIntuition->FreeClass(cl)); } uint32 dispatchmyTextLabel(Class * cl, Object * o, Msg msg) { struct localObjData *lod; Object *newobj; uint32 retval; switch (msg->MethodID) { case OM_NEW: /* Pass up to the superclass... */ if ((newobj = (Object *) IIntuition->IDoSuperMethodA(cl, o, msg))) { struct TagItem *attrs = ((struct opSet *) msg)->ops_AttrList; struct DrawInfo *drinfo; /* Get the DrawInfo */ drinfo = (struct DrawInfo *) IUtility->GetTagData(SYSIA_DrawInfo, NULL, attrs); /* Get the instance data */ lod = (struct localObjData *)INST_DATA(cl, newobj); /* Establish defaults */ IM(newobj)->PlanePick = 1; lod->lod_Mode = JAM1; /* Set the attributes */ setmyTextLabelAttrs(cl, newobj, (struct opSet *) msg); /* Get the bounding rectangle of the label */ getContentsExtent(cl, newobj, drinfo); } retval = (uint32) newobj; break; case OM_GET: retval = getmyTextLabelAttr(cl, o, (struct opGet *) msg); break; case OM_UPDATE: case OM_SET: /* Do the superclass first */ retval = IIntuition->IDoSuperMethodA(cl, o, msg); /* Call our set routines */ retval += setmyTextLabelAttrs(cl, o, (struct opSet *) msg); break; case IM_DRAW: /* draw the label */ case IM_DRAWFRAME: /* drawmyTextLabel() will take care of extra framing info */ retval = drawmyTextLabel(cl, o, (struct impDraw *) msg); break; /* Let the superclass handle everything else */ default: retval = (uint32) IIntuition->IDoSuperMethodA(cl, o, msg); break; } return (retval); } /* Set attributes of an object */ uint32 setmyTextLabelAttrs(Class * cl, Object * o, struct opSet * msg) { struct localObjData *lod = (struct localObjData *)INST_DATA(cl, o); struct TagItem *tags = msg->ops_AttrList; struct TagItem *tstate; struct TagItem *tag; uint32 tidata; /* process rest */ tstate = tags; while ((tag = IUtility->NextTagItem(&tstate))) { tidata = tag->ti_Data; switch (tag->ti_Tag) { case IA_FGPen: IM(o)->PlanePick = (uint8) tidata; break; case IA_BGPen: IM(o)->PlaneOnOff = (uint8) tidata; break; /* Must be a TextFont pointer. */ case IA_Font: /* Set the font */ lod->lod_Font = (struct TextFont *) tidata; break; /* Drawing mode to use */ case IA_Mode: lod->lod_Mode = (uint8) tidata; break; case IA_Data: IM(o)->ImageData = (uint16 *) tidata; lod->lod_Key = GetLabelKeystroke((STRPTR) tidata); break; } } return (1L); } /* Inquire attributes of an object */ uint32 getmyTextLabelAttr(Class * cl, Object * o, struct opGet * msg) { struct localObjData *lod = (struct localObjData *)INST_DATA(cl, o); switch (msg->opg_AttrID) { case IA_Font: *msg->opg_Storage = (uint32) lod->lod_Font; break; case IA_Mode: *msg->opg_Storage = (uint32) lod->lod_Mode; break; /* Let the superclass try */ default: return ((uint32) IIntuition->IDoSuperMethodA(cl, o, (Msg)msg)); } return (1L); } uint32 drawmyTextLabel(Class * cl, Object * o, struct impDraw * msg) { struct localObjData *lod = (struct localObjData *)INST_DATA(cl, o); STRPTR label = (STRPTR) IM(o)->ImageData; struct DrawInfo *di = msg->imp_DrInfo; struct RastPort *rp = msg->imp_RPort; struct TextFont *tf = NULL; int16 len = strlen(label); int16 left, top; int16 height = 0; int16 width = 0; int16 i; /* Clear the key */ lod->lod_Key = NULL; /* Get a pointer to the font to use */ if (!(tf = lod->lod_Font) && di) { tf = di->dri_Font; } /* Make sure we have font pointer */ if (tf) { /* Set the font */ IGraphics->SetFont(rp, tf); } /* Figure out our coordinates */ top = msg->imp_Offset.Y + IM(o)->TopEdge + rp->TxBaseline; left = msg->imp_Offset.X + IM(o)->LeftEdge; /* See if we have frame information. */ if (msg->MethodID == IM_DRAWFRAME) { /* Center the text inside the frame. */ width = msg->imp_Dimensions.Width; height = msg->imp_Dimensions.Height; top += ((height - IM(o)->Height) > 0) ? ((height - IM(o)->Height) / 2) : 0; left += ((width - IM(o)->Width) > 0) ? ((width - IM(o)->Width) / 2) : 0; } /* Set the colors */ IGraphics->SetAPen(rp, IM(o)->PlanePick); IGraphics->SetBPen(rp, IM(o)->PlaneOnOff); /* Set the drawing mode */ IGraphics->SetDrMd(rp, lod->lod_Mode); /* Move to the start */ IGraphics->Move(rp, left, top); /* Step through string */ for (i = 0; i < (len - 1); i++) { /* Is this an '_' ? */ if (label[i] == '_') { int16 bot = (top + rp->TxHeight - rp->TxBaseline); int16 mark; /* Draw the first part of the string */ IGraphics->Text(rp, label, i); /* Remember where we are in the string */ mark = rp->cp_x; /* Draw the underscore */ IGraphics->Move(rp, mark, bot); IGraphics->Draw(rp, (mark + IGraphics->TextLength(rp, &label[(i + 1)], 1L) - 2), bot); /* Return to where we were */ IGraphics->Move(rp, mark, top); /* * Draw the rest of the string. This one is done last so that the cursor * could be positioned after the text. */ IGraphics->Text(rp, &label[(i + 1)], (len - i - 1)); /* Return the underlined character */ lod->lod_Key = (uint16) label[i]; } } /* Do we have an underscore? */ if (!lod->lod_Key) { /* Didn't find an '_' sign */ IGraphics->Text(rp, label, len); } return (1L); } uint16 GetLabelKeystroke(STRPTR label) { LONG count = (label) ? strlen(label) : 0L; LONG i; /* Search for an _ sign */ for (i = 0; i < (count - 1); i++) { /* Did we find an _ sign? */ if (label[i] == '_') { return ((uint16) label[(i + 1)]); } } return (0); } /* TextExtent that honors the '_' as being a non-printable character (once) */ int16 aTextExtent(struct RastPort * rp, STRPTR string, LONG count, struct TextExtent * te) { int16 retval = FALSE; STRPTR buffer; LONG i; /* Allocate a temporary buffer */ if ((buffer = (STRPTR)IExec->AllocVecTags((count + 1), AVT_ClearWithValue, 0, TAG_END))) { /* Step through string */ for (i = 0; i < count; i++) { /* Is this an '_' sign? */ if (string[i] == '_') { /* Add the rest of the label to the buffer */ strcat (buffer, &string[(i + 1)]); /* Adjust the length of the string. */ count--; break; } else { /* Copy each character over, until we reach the _ mark */ buffer[i] = string[i]; } } /* Get the extent */ IGraphics->TextExtent(rp, buffer, count, te); /* Free the temporary buffer */ IExec->FreeVec (buffer); /* Show that we were successful */ retval = TRUE; } /* Return whatever textextent returned */ return (retval); } static VOID getContentsExtent(Class * cl, Object * o, struct DrawInfo * drinfo) { struct localObjData *lod = (localObjData *)INST_DATA(cl, o); struct TextExtent te = {0, 0, {0, 0, 0, 0}}; struct RastPort rp; STRPTR label; /* maybe look at some flags to handle other types of text someday */ if ((label = (STRPTR) IM(o)->ImageData)) { /* Initialize the RastPort */ IGraphics->InitRastPort(&rp); if (lod->lod_Font) { IGraphics->SetFont(&rp, lod->lod_Font); } else if (drinfo && drinfo->dri_Font) { IGraphics->SetFont(&rp, drinfo->dri_Font); } /* Get the rectangle for the label */ aTextExtent(&rp, label, strlen(label), &te); /* Set the image structure */ IM(o)->Width = te.te_Width; IM(o)->Height = te.te_Height; } else { IM(o)->Width = IM(o)->Height = 0; } }