home *** CD-ROM | disk | FTP | other *** search
Wrap
/* ** $Id: termGadTools.c,v 1.3 92/08/15 20:14:05 olsen Sta Locker: olsen $ ** $Revision: 1.3 $ ** $Date: 92/08/15 20:14:05 $ ** ** GadTools object management support routines ** ** Copyright ⌐ 1990-1992 by Olaf `Olsen' Barthel & MXM ** All Rights Reserved */ /* Some includes for starters. */ #include <intuition/intuition.h> #include <libraries/gadtools.h> #include <intuition/sghooks.h> #include <utility/tagitem.h> #include <exec/memory.h> #include <clib/intuition_protos.h> #include <clib/utility_protos.h> #include <clib/exec_protos.h> #include <stdarg.h> /* User interface definitions. */ #define SZLV_Display 1 /* Listview includes display */ #define SZLV_String 2 /* Listview includes string */ #define SZ_Adjust TAG_USER+1 /* Adjust object */ #define SZ_AutoWidth TAG_USER+2 /* Use default width? */ #define SZ_AlignExtra TAG_USER+3 /* Add extra space to top edge */ #define SZ_NewColumn TAG_USER+4 /* Start new column */ #define SZ_Lines TAG_USER+5 /* Number of lines in object */ #define SZ_Chars TAG_USER+6 /* Number of chars (width) in object */ #define SZ_AlignLeft TAG_USER+7 /* Align to left border */ #define SZ_AlignRight TAG_USER+8 /* Align to right border */ #define SZ_AlignCentre TAG_USER+9 /* Centre it */ #define SZ_AlignBottom TAG_USER+10 /* Align to window bottom */ #define SZ_GroupCount TAG_USER+11 /* Create a group with N objects */ #define SZ_GroupNext TAG_USER+12 /* Skip to next position */ #define SZ_SetLeft TAG_USER+13 /* Place left to current object, don't touch the left edge position, though. */ #define SZ_SetBelow TAG_USER+14 /* Place below current object, don't touch the top edge position, though. */ #define SZ_UseLeft TAG_USER+15 /* Use this coordinate as left edge. */ #define SZ_UseTop TAG_USER+16 /* Use this coordinate as top edge. */ #define SZ_UseWidth TAG_USER+17 /* Use this gadget width. */ #define SZ_UseHeight TAG_USER+18 /* Use this gadget height. */ #define SZ_FullWidth TAG_USER+19 /* Use full window width for gadget. */ #define SZ_FullHeight TAG_USER+20 /* Use full window height for gadget. */ /* Some #define values which may not yet be available in * every include file set. */ #ifndef GTMN_NewLookMenus #define GTMN_NewLookMenus (GT_TagBase+67) #endif /* GTMN_NewLookMenus */ #ifndef WA_NewLookMenus #define WA_NewLookMenus (WA_Dummy+0x30) #endif /* WA_NewLookMenus */ #ifndef GTCB_Scaled #define GTCB_Scaled GT_TagBase+68 #endif /* GTCB_Scaled */ #ifndef GTMX_Scaled #define GTMX_Scaled GT_TagBase+69 #endif /* GTMX_Scaled */ enum { COLOUR_AMIGA,COLOUR_EIGHT,COLOUR_SIXTEEN,COLOUR_MONO }; /* term configuration. */ struct Configuration { /* Serial Preferences. */ ULONG BaudRate; BYTE BitsPerChar; BYTE Parity; BYTE StopBits; BYTE Handshaking; BYTE Duplex; BYTE HighSpeed; ULONG BreakLength; UBYTE SerialDevice[40]; LONG UnitNumber; /* Modem Preferences. */ UBYTE ModemInit[80]; UBYTE ModemExit[80]; UBYTE ModemHangup[80]; UBYTE DialPrefix[80]; LONG RedialDelay; LONG DialRetries; LONG DialTimeout; BYTE ConnectAutoCapture; BYTE ConnectAutoBaud; BYTE LogActions; UBYTE NoCarrier[16]; UBYTE Connect[16]; UBYTE Voice[16]; UBYTE Ring[16]; UBYTE Busy[16]; /* Transfer Preferences. */ UBYTE Protocol[40]; /* Startup macro. */ UBYTE StartupMacro[256]; /* Macro Preferences. */ UBYTE MacroFile[256]; /* Screen Preferences. */ ULONG DisplayMode; UWORD Colours[16]; BYTE MakeScreenPublic; BYTE ShanghaiWindows; /* Terminal Preferences. */ BYTE CaptureFilter; BYTE DestructiveBackspace; BYTE AudibleBell; BYTE VisibleBell; BYTE EightyColumns; BYTE DisableBlinking; BYTE SendCR; BYTE SendLF; BYTE ColourMode; BYTE Emulation; BYTE Font; /* Emulation control. */ BYTE CursorApp; BYTE FontScale; BYTE JumpScroll; BYTE AutoWrap; BYTE CursorWrap; BYTE NewLine; BYTE InsertChar; BYTE NumApp; /* Path Preferences. */ UBYTE DefaultStorage[256]; UBYTE TextUploadPath[256]; UBYTE TextDownloadPath[256]; UBYTE ASCIIUploadPath[256]; UBYTE ASCIIDownloadPath[256]; UBYTE BinaryUploadPath[256]; UBYTE BinaryDownloadPath[256]; UBYTE CapturePath[256]; UBYTE LogFile[256]; UBYTE Editor[256]; UBYTE BeepSound[256]; /* Extension in version 1.9b */ BYTE SwapBSDelete; BYTE StripBit8; /* Some more extensions... */ BYTE RasterEnabled; UBYTE EmulationName[256]; /* Up-/Download Macros. */ UBYTE UploadMacro[256]; UBYTE DownloadMacro[256]; /* Default fast! macro file. */ UBYTE FastMacroFile[256]; /* Program priority. */ BYTE Priority; /* Override transfer path. */ BYTE OverridePath; /* Backup config between switching to phone entries. */ BYTE BackupConfig; /* ZModem auto upload panel enabled? */ BYTE AutoUpload; /* No dialtone string. */ UBYTE NoDialTone[16]; /* Check carrier upon `CARRIER LOST' message. */ BYTE CheckCarrier; /* Display the screen title bar? */ BYTE TitleBar; /* Display the status lines? */ BYTE StatusLine; BYTE DropDTR; /* Custom keymap file name. */ UBYTE KeyMapName[40]; /* Serial buffer size. */ LONG SerBuffSize; /* Maximum log book buffer size. */ LONG MaxLogBuffSize; /* Is the buffering enabled? */ BYTE BufferEnabled; /* Receive CR/LF as... */ BYTE ReceiveCR; BYTE ReceiveLF; /* Set `archived' bit on uploaded files. */ BYTE SetArchivedBit; /* Open the fast! macro panel on startup? */ BYTE OpenFastMacroPanel; /* Pass xON/xOFF through to modem? */ BYTE PassThrough; /* Use system DisplayBeep()? */ BYTE SystemBeep; BYTE Pad; /* Answerback message. */ UBYTE AnswerBack[41]; BYTE Pad2; /* Font settings. */ UBYTE FontName[32]; WORD FontHeight; }; /* External data. */ extern struct Library *GadToolsBase, *DiskfontBase; extern struct Gadget *ActiveGadget; extern struct Configuration Config; extern UBYTE SharedBuffer[]; extern APTR VisualInfo; extern LONG InterWidth, InterHeight; /* This structure will help us to remember the current state of * a GadTools object. */ struct GadgetSupportInfo { struct GadgetSupportInfo *PointBack; /* Points back to itself. */ struct Gadget *Gadget; /* Points back to the host. */ WORD Kind; /* Item type (BUTTON_KIND, STRING_KIND, etc.) */ UBYTE Key; /* The key to press. */ BYTE ReadOnly; /* LISTVIEW_KIND only: is this a read-only object? */ LONG Current, /* Current state or counter. */ Min, /* Minimum value for `Current'. */ Max; /* Maximum value for `Current'. */ }; /* A text box for several lines of text. */ struct TextBox { struct TextBox *NextBox; /* Next box in chain. */ LONG Left,Top, /* Position and size. */ Width,Height; LONG LineWidth, /* Line width in pixels. */ LineHeight; /* Line height in pixels. */ LONG NumChars, /* Number of chars per line. */ NumLines; /* Number of lines. */ STRPTR *Title, /* Line titles. */ *Text; /* Line texts. */ WORD TextPen; }; /* Sizing data. */ STATIC struct RastPort *SZ_RPort; STATIC struct TextFont *SZ_TextFont; STATIC struct Screen *SZ_Screen; STATIC LONG SZ_Left, SZ_Top, SZ_WindowWidth, SZ_WindowHeight; SZ_CurrentLeft, SZ_CurrentTop, SZ_CurrentWidth, SZ_MaxWidth, SZ_GroupDelta, SZ_GroupX, SZ_WidthMax, SZ_TextPen; /* Local routines. */ struct Gadget * CreateGadget(ULONG Kind,struct Gadget *Previous,struct NewGadget *New,...); VOID FreeGadgets(struct Gadget *GadgetList); VOID GT_SetGadgetAttrs(struct Gadget *Gadget,struct Window *Window,struct Requester *Requester,...); VOID GT_ReplyIMsg(struct IntuiMessage *Message); VOID KeySelect(struct Gadget **GadgetList,WORD Last,UBYTE Key,struct Window *Window,struct Gadget **Gadget,ULONG *Class,LONG *Code); /* Sizing routines. */ LONG SZ_GetWindowWidth(VOID); LONG SZ_GetWindowHeight(VOID); LONG SZ_GetLeftEdge(VOID); LONG SZ_GetTopEdge(VOID); VOID __regargs SZ_SetTopEdge(LONG Top); VOID __regargs SZ_SetLeftEdge(LONG Left); VOID __regargs SZ_SetAbsoluteTop(LONG Top); VOID __regargs SZ_SetAbsoluteLeft(LONG Left); VOID __regargs SZ_SetWidth(LONG Width); LONG SZ_ResetMaxWidth(VOID); VOID __regargs SZ_UpdateMaxWidth(UBYTE Type,STRPTR Title,LONG Chars,STRPTR *Choices); VOID __regargs SZ_GetDimension(LONG *Width,LONG *Height); LONG __regargs SZ_TextWidth(STRPTR String); VOID __regargs SZ_AddLeftOffset(LONG Offset); LONG __stdargs SZ_LeftOffsetN(LONG DataArray,...); LONG __regargs SZ_LeftOffsetDelta(LONG From,LONG To); VOID SZ_SizeCleanup(); BYTE __regargs SZ_SizeSetup(struct Screen *Screen,struct TextAttr *TextAttr,BYTE Title); LONG __regargs SZ_Height(UBYTE Type,LONG Lines,BYTE Display); LONG __regargs SZ_Width(UBYTE Type,STRPTR Title,LONG Chars,STRPTR *Choices); /* Text box routines. */ VOID __regargs SZ_FreeBox(struct TextBox *Box); VOID __regargs SZ_FreeBoxes(struct TextBox *FirstBox); LONG __regargs SZ_BoxWidth(LONG Chars); LONG __regargs SZ_BoxHeight(LONG Lines); struct TextBox * __stdargs SZ_CreateTextBox(struct TextBox **FirstBox,...); VOID __stdargs SZ_SetBoxTitles(struct TextBox *Box,STRPTR Array,...); VOID __stdargs SZ_PrintLine(struct RastPort *RPort,struct TextBox *Box,LONG Line,STRPTR String,...); VOID __regargs SZ_DrawBox(struct RastPort *RPort,struct TextBox *Box); VOID __regargs SZ_DrawBoxes(struct RastPort *RPort,struct TextBox *FirstBox); /* The original gadtools.library routines. */ struct Gadget * OldCreateGadgetA(ULONG,struct Gadget *,struct NewGadget *,struct TagItem *); VOID OldFreeGadget(struct Gadget *); VOID OldGT_SetGadgetAttrsA(struct Gadget *,struct Window *,struct Requester *,struct TagItem *); VOID OldGT_ReplyIMsg(struct IntuiMessage *); /* Pragma calls: the easy way. */ #pragma libcall GadToolsBase OldCreateGadgetA 1E A98004 #pragma libcall GadToolsBase OldFreeGadgets 24 801 #pragma libcall GadToolsBase OldGT_SetGadgetAttrsA 2A BA9804 #pragma libcall GadToolsBase OldGT_ReplyIMsg 4E 901 /* CreateGadget(): * * A frontend to the original routine. */ struct Gadget * CreateGadget(ULONG Kind,struct Gadget *Previous,struct NewGadget *New,...) { STATIC struct NewGadget Backup; va_list VarArgs; struct TagItem *TagList, *ThisTag, MoreTags[3]; struct GadgetSupportInfo *Info = NULL; WORD i; UBYTE Underscore = 0; struct Gadget *Result; /* Get the tag item array. */ va_start(VarArgs,New); /* Make a backup copy of the original NewGadget structure, * we may want to modify it. */ CopyMem(New,&Backup,sizeof(struct NewGadget)); New = &Backup; /* Get the tag item list. */ TagList = (struct TagItem *)VarArgs; /* Try to find the SZ_Adjust tag item. If found, we are to * apply our formatting functions to it. */ if(ThisTag = FindTagItem(SZ_Adjust,TagList)) { if(ThisTag -> ti_Data) { STRPTR *Labels = NULL; LONG Width, Height, Left = SZ_CurrentLeft; BYTE AutoWidth = FALSE, MoveDown = TRUE, SaveWidth = TRUE, SetLeft = FALSE, SetBelow = FALSE; /* Are we to leave the left edge untouched? */ if(ThisTag = FindTagItem(SZ_SetLeft,TagList)) SetLeft = ThisTag -> ti_Data; /* Are we to leave the top edge untouched? */ if(ThisTag = FindTagItem(SZ_SetBelow,TagList)) SetBelow = ThisTag -> ti_Data; /* Are we to align the object to the * window bottom? */ if(ThisTag = FindTagItem(SZ_AlignBottom,TagList)) { if(ThisTag -> ti_Data) SZ_CurrentTop = SZ_WindowHeight; } /* Are we to add extra space to the * object top edge? */ if(ThisTag = FindTagItem(SZ_AlignExtra,TagList)) { if(ThisTag -> ti_Data) SZ_CurrentTop += InterHeight; } /* Are we to start a new column? */ if(ThisTag = FindTagItem(SZ_NewColumn,TagList)) { if(ThisTag -> ti_Data) { SZ_CurrentTop = SZ_Top; Left = Left + SZ_MaxWidth + InterWidth; SZ_MaxWidth = 0; } } /* Is the object to contain a certain * number of lines? */ if(ThisTag = FindTagItem(SZ_Lines,TagList)) { LONG Lines = (LONG)ThisTag -> ti_Data; /* Is it a listview object? */ if(Kind == LISTVIEW_KIND) { /* Determine height of object. */ if(ThisTag = FindTagItem(GTLV_ShowSelected,TagList)) { if(ThisTag -> ti_Data) Height = SZ_Height(Kind,Lines,SZLV_String); else Height = SZ_Height(Kind,Lines,SZLV_Display); } else Height = SZ_Height(Kind,Lines,NULL); } else Height = SZ_Height(Kind,Lines,NULL); } else { /* If this is a MX kind object, * determine the number of lines * by looking at the labels. */ if(ThisTag = FindTagItem(GTMX_Labels,TagList)) { STRPTR *Choices; LONG Lines = 0; Labels = Choices = (STRPTR *)ThisTag -> ti_Data; while(*Choices++) Lines++; Height = SZ_Height(Kind,Lines,NULL); } else Height = SZ_Height(Kind,0,NULL); } /* Is the object width derived from * certain magical calculations or * is it as wide as the default width? */ if(ThisTag = FindTagItem(SZ_AutoWidth,TagList)) AutoWidth = ThisTag -> ti_Data; /* Determine the width of the object. */ if(!AutoWidth) { STRPTR *Choices = NULL, Title = NULL; LONG Chars = 0; /* Determine number of characters in * this object. */ if(ThisTag = FindTagItem(SZ_Chars,TagList)) Chars = ThisTag -> ti_Data; /* If this is a button object, * calculate the width by looking * at the title. */ if(Kind == BUTTON_KIND && New -> ng_GadgetText) Title = New -> ng_GadgetText; /* If this is a cycle object, * take a look at the labels. */ if(ThisTag = FindTagItem(GTCY_Labels,TagList)) Choices = (STRPTR *)ThisTag -> ti_Data; /* If this is a listview object, * take a look at the list. */ if(ThisTag = FindTagItem(GTLV_Labels,TagList)) { if(ThisTag -> ti_Data != ~0) { struct List *List = (struct List *)ThisTag -> ti_Data; struct Node *Node; LONG Len; Node = List -> lh_Head; while(Node -> ln_Succ) { if((Len = strlen(Node -> ln_Name)) > Chars) Chars = Len; Node = Node -> ln_Succ; } } } /* Determine object width. */ Width = SZ_Width(Kind,Title,Chars,Choices); } else { /* Use the default width. */ Width = SZ_CurrentWidth; /* A checkbox object has a * fixed width. We don't want * any other objects to share * it. */ if(Kind == CHECKBOX_KIND) { Width = SZ_Width(Kind,NULL,0,NULL); SaveWidth = FALSE; } } /* Are we to align this object to * the left window edge? */ if(ThisTag = FindTagItem(SZ_AlignLeft,TagList)) { if(ThisTag -> ti_Data) { Left = SZ_Left; MoveDown = FALSE; } } /* Are we to use a specific object width? */ if(ThisTag = FindTagItem(SZ_UseWidth,TagList)) Width = ThisTag -> ti_Data; /* Are we to use a specific object height? */ if(ThisTag = FindTagItem(SZ_UseHeight,TagList)) Height = ThisTag -> ti_Data; /* Are we to align this object to the * right window edge? */ if(ThisTag = FindTagItem(SZ_AlignRight,TagList)) { if(ThisTag -> ti_Data) { Left = SZ_WindowWidth - INTERWIDTH - Width; MoveDown = FALSE; } } /* Are we to centre the object in * the window? */ if(ThisTag = FindTagItem(SZ_AlignCentre,TagList)) { if(ThisTag -> ti_Data) { Left = (SZ_WindowWidth - Width) / 2; MoveDown = FALSE; } } /* Are we to build a horizontal group * using the following objects? */ if(ThisTag = FindTagItem(SZ_GroupCount,TagList)) { LONG Count = ThisTag -> ti_Data, Width = SZ_WindowWidth; /* Use a specific left edge? */ if(ThisTag = FindTagItem(SZ_UseLeft,TagList)) { Width -= ThisTag -> ti_Data - InterWidth; SZ_GroupDelta = SZ_CurrentWidth + ((Width - 2 * InterWidth) - (Count * SZ_CurrentWidth)) / (Count - 1); SZ_GroupX = Left = ThisTag -> ti_Data; } else { SZ_GroupDelta = SZ_CurrentWidth + ((Width - 2 * InterWidth) - (Count * SZ_CurrentWidth)) / (Count - 1); SZ_GroupX = Left = SZ_Left; } MoveDown = FALSE; } else { if(ThisTag = FindTagItem(SZ_UseLeft,TagList)) Left = ThisTag -> ti_Data; } /* Skip to the next group item position? */ if(ThisTag = FindTagItem(SZ_GroupNext,TagList)) { if(ThisTag -> ti_Data) { SZ_GroupX += SZ_GroupDelta; Left = SZ_GroupX; MoveDown = FALSE; } } /* Determine default label placement. */ switch(Kind) { case MX_KIND: case CHECKBOX_KIND: New -> ng_Flags = (New -> ng_Flags & ~(PLACETEXT_LEFT|PLACETEXT_RIGHT|PLACETEXT_ABOVE|PLACETEXT_BELOW|PLACETEXT_IN)) | PLACETEXT_LEFT; SaveWidth = FALSE; break; default: if(New -> ng_Flags & PLACETEXT_ABOVE) SZ_CurrentTop += INTERHEIGHT + SZ_TextFont -> tf_YSize; break; } /* Gadget is to be as wide as the entire window? */ if(ThisTag = FindTagItem(SZ_FullWidth,TagList)) { if(ThisTag -> ti_Data) Width = SZ_WindowWidth - 2 * INTERWIDTH; } /* Gadget is to be as high as the entire window? */ if(ThisTag = FindTagItem(SZ_FullHeight,TagList)) { if(ThisTag -> ti_Data) Height = SZ_WindowHeight - InterHeight - SZ_Top; } /* Use a specific top edge? */ if(ThisTag = FindTagItem(SZ_UseTop,TagList)) SZ_CurrentTop = ThisTag -> ti_Data; /* Fill in the NewGadget. */ New -> ng_LeftEdge = Left; New -> ng_TopEdge = SZ_CurrentTop; New -> ng_Width = Width; New -> ng_Height = Height; /* Add the default tags. */ switch(Kind) { case PALETTE_KIND: MoreTags[0] . ti_Tag = GTPA_IndicatorWidth; MoreTags[0] . ti_Data = Width / 4; MoreTags[1] . ti_Tag = GTPA_IndicatorHeight; MoreTags[1] . ti_Data = Height; MoreTags[2] . ti_Tag = TAG_MORE; MoreTags[2] . ti_Data = (ULONG)TagList; TagList = MoreTags; break; case LISTVIEW_KIND: MoreTags[0] . ti_Tag = GTLV_ScrollWidth; MoreTags[0] . ti_Data = 2 + 2 * SZ_TextFont -> tf_XSize + 2; MoreTags[1] . ti_Tag = TAG_MORE; MoreTags[1] . ti_Data = (ULONG)TagList; TagList = MoreTags; break; case CHECKBOX_KIND: MoreTags[0] . ti_Tag = GTCB_Scaled; MoreTags[0] . ti_Data = TRUE; MoreTags[1] . ti_Tag = TAG_MORE; MoreTags[1] . ti_Data = (ULONG)TagList; TagList = MoreTags; break; case MX_KIND: MoreTags[0] . ti_Tag = GTMX_Scaled; MoreTags[0] . ti_Data = TRUE; MoreTags[1] . ti_Tag = TAG_MORE; MoreTags[1] . ti_Data = (ULONG)TagList; TagList = MoreTags; break; default: break; } /* Restore default object width if necessary. */ if(SaveWidth) SZ_CurrentWidth = Width; /* Are we to leave the top edge untouched? */ if(SetBelow) MoveDown = FALSE; if(MoveDown) { /* Move down to next object. */ SZ_CurrentTop = SZ_CurrentTop + Height + InterHeight; /* Extend window height if necessary. */ if(SZ_CurrentTop > SZ_WindowHeight) SZ_WindowHeight = SZ_CurrentTop; } else { /* Extend window height if necessary. */ if(SZ_CurrentTop + Height + InterHeight > SZ_WindowHeight) SZ_WindowHeight = SZ_CurrentTop + Height + InterHeight; SZ_MaxWidth = 0; } /* Update maximum object width. */ if(Width > SZ_MaxWidth) SZ_MaxWidth = Width; /* Extend window width if necessary. */ if(Left + SZ_MaxWidth + INTERWIDTH > SZ_WindowWidth) SZ_WindowWidth = Left + SZ_MaxWidth + INTERWIDTH; /* Are we to leave the left edge untouched? */ if(!SetLeft) SZ_CurrentLeft = Left; } } /* Now for keystroke activation... */ switch(Kind) { case STRING_KIND: case INTEGER_KIND: case BUTTON_KIND: case CHECKBOX_KIND: case CYCLE_KIND: case LISTVIEW_KIND: case MX_KIND: case PALETTE_KIND: case SCROLLER_KIND: case SLIDER_KIND: /* Do we have an underscore character to * play with? */ if(ThisTag = FindTagItem(GT_Underscore,TagList)) Underscore = ThisTag -> ti_Data; if(Underscore) { /* Do we have a gadget label? */ if(New -> ng_GadgetText) { /* Look for the underscore * character... */ for(i = 0 ; i < strlen(New -> ng_GadgetText) ; i++) { if(New -> ng_GadgetText[i] == Underscore) { /* Is it a printable character? */ if(New -> ng_GadgetText[i + 1] > ' ') { /* Create information buffer. */ if(Info = (struct GadgetSupportInfo *)AllocMem(sizeof(struct GadgetSupportInfo),MEMF_ANY|MEMF_CLEAR)) { /* Set up the default data. */ Info -> PointBack = Info; Info -> Kind = Kind; Info -> Key = New -> ng_GadgetText[i + 1]; /* Add object-specific information. */ if(Info -> Kind == PALETTE_KIND) { Info -> Current = 1; Info -> Max = 1; } if(Info -> Kind == LISTVIEW_KIND) Info -> Current = ~0; break; } } } } } } break; default: break; } /* Fill in object info if available. */ New -> ng_UserData = Info; /* Did we create any object info? */ if(Info) { struct Node *Node; struct List *List; LONG Count; STRPTR *Strings; /* The following code takes care of object-specific * characteristics, such as currently selected items, * current value, minimum value, maximum value, etc. * and places them in the gadget info. */ switch(Kind) { case CHECKBOX_KIND: if(ThisTag = FindTagItem(GTCB_Checked,TagList)) Info -> Current = ThisTag -> ti_Data; break; case CYCLE_KIND: if(ThisTag = FindTagItem(GTCY_Active,TagList)) Info -> Current = ThisTag -> ti_Data; if(ThisTag = FindTagItem(GTCY_Labels,TagList)) { Count = 0; if(Strings = (STRPTR *)ThisTag -> ti_Data) { while(Strings[Count]) Count++; } if(Count) Info -> Max = Count - 1; } break; case LISTVIEW_KIND: if(ThisTag = FindTagItem(GTLV_Selected,TagList)) Info -> Current = ThisTag -> ti_Data; if(ThisTag = FindTagItem(GTLV_ReadOnly,TagList)) { if(ThisTag -> ti_Data) Info -> ReadOnly = TRUE; } if(ThisTag = FindTagItem(GTLV_ShowSelected,TagList)) { if(ThisTag -> ti_Data) Info -> ReadOnly = FALSE; } if(ThisTag = FindTagItem(GTLV_Labels,TagList)) { Count = 0; if(ThisTag -> ti_Data && ThisTag -> ti_Data != ~0) { List = (struct List *)ThisTag -> ti_Data; Node = List -> lh_Head; while(Node -> ln_Succ) { Count++; Node = Node -> ln_Succ; } } if(Count) Info -> Max = Count - 1; } break; case MX_KIND: if(ThisTag = FindTagItem(GTMX_Active,TagList)) Info -> Current = ThisTag -> ti_Data; if(ThisTag = FindTagItem(GTMX_Labels,TagList)) { Count = 0; if(Strings = (STRPTR *)ThisTag -> ti_Data) { while(Strings[Count]) Count++; } if(Count) Info -> Max = Count - 1; } break; case SCROLLER_KIND: if(ThisTag = FindTagItem(GTSC_Top,TagList)) Info -> Current = ThisTag -> ti_Data; if(ThisTag = FindTagItem(GTSC_Total,TagList)) Info -> Max = ThisTag -> ti_Data; break; case SLIDER_KIND: if(ThisTag = FindTagItem(GTSL_Level,TagList)) Info -> Current = ThisTag -> ti_Data; if(ThisTag = FindTagItem(GTSL_Min,TagList)) Info -> Min = ThisTag -> ti_Data; if(ThisTag = FindTagItem(GTSL_Max,TagList)) Info -> Max = ThisTag -> ti_Data; break; case PALETTE_KIND: if(ThisTag = FindTagItem(GTPA_Color,TagList)) Info -> Current = ThisTag -> ti_Data; if(ThisTag = FindTagItem(GTPA_Depth,TagList)) Info -> Max = (1 << ((LONG)ThisTag -> ti_Data)) - 1; break; default: break; } /* Create the object and attach the info to it. */ if(Result = OldCreateGadgetA(Kind,Previous,New,TagList)) Info -> Gadget = Result; else FreeMem(Info,sizeof(struct GadgetSupportInfo)); } else Result = OldCreateGadgetA(Kind,Previous,New,TagList); va_end(VarArgs); return(Result); } /* GT_SetGadgetAttrs(): * * A frontend to the original routine. */ VOID GT_SetGadgetAttrs(struct Gadget *Gadget,struct Window *Window,struct Requester *Requester,...) { va_list VarArgs; struct TagItem *TagList, *ThisTag; struct GadgetSupportInfo *Info; /* Get the tag item list. */ va_start(VarArgs,Requester); TagList = (struct TagItem *)VarArgs; /* Does the object in question have an info structure attached? */ if(Info = (struct GadgetSupportInfo *)Gadget -> UserData) { /* Does the data look sensible? */ if(Info -> PointBack == Info && Info -> Gadget == Gadget) { struct Node *Node; struct List *List; LONG Count; STRPTR *Strings; /* Update object-specific information. */ switch(Info -> Kind) { case CHECKBOX_KIND: if(ThisTag = FindTagItem(GTCB_Checked,TagList)) Info -> Current = ThisTag -> ti_Data; break; case CYCLE_KIND: if(ThisTag = FindTagItem(GTCY_Active,TagList)) Info -> Current = ThisTag -> ti_Data; if(ThisTag = FindTagItem(GTCY_Labels,TagList)) { Count = 0; if(Strings = (STRPTR *)ThisTag -> ti_Data) { while(Strings[Count]) Count++; } if(Count) Info -> Max = Count - 1; else Info -> Max = 0; } break; case LISTVIEW_KIND: if(ThisTag = FindTagItem(GTLV_Selected,TagList)) Info -> Current = ThisTag -> ti_Data; if(ThisTag = FindTagItem(GTLV_Labels,TagList)) { Count = 0; if(ThisTag -> ti_Data && ThisTag -> ti_Data != ~0) { List = (struct List *)ThisTag -> ti_Data; Node = List -> lh_Head; while(Node -> ln_Succ) { Count++; Node = Node -> ln_Succ; } } if(Count) Info -> Max = Count - 1; else Info -> Max = 0; } break; case PALETTE_KIND: if(ThisTag = FindTagItem(GTPA_Color,TagList)) Info -> Current = ThisTag -> ti_Data; break; case MX_KIND: if(ThisTag = FindTagItem(GTMX_Active,TagList)) Info -> Current = ThisTag -> ti_Data; break; case SCROLLER_KIND: if(ThisTag = FindTagItem(GTSC_Top,TagList)) Info -> Current = ThisTag -> ti_Data; if(ThisTag = FindTagItem(GTSC_Total,TagList)) Info -> Max = ThisTag -> ti_Data; break; case SLIDER_KIND: if(ThisTag = FindTagItem(GTSL_Level,TagList)) Info -> Current = ThisTag -> ti_Data; if(ThisTag = FindTagItem(GTSL_Min,TagList)) Info -> Min = ThisTag -> ti_Data; break; default: break; } } } /* Call the original routine. */ OldGT_SetGadgetAttrsA(Gadget,Window,Requester,TagList); va_end(VarArgs); } /* FreeGadgets(struct Gadget *GadgetList): * * A frontend to the original routine. */ VOID FreeGadgets(struct Gadget *GadgetList) { struct Gadget *Gadget = GadgetList; struct GadgetSupportInfo *Info; /* Run down the gadget list. */ while(Gadget) { /* Does it have an info structure attached?*/ if(Info = (struct GadgetSupportInfo *)Gadget -> UserData) { /* Does the data make sense? */ if(Info -> PointBack == Info && Info -> Gadget == Gadget) FreeMem(Info,sizeof(struct GadgetSupportInfo)); } /* Skip to next object. */ Gadget = Gadget -> NextGadget; } OldFreeGadgets(GadgetList); } /* GT_ReplyIMsg(struct IntuiMessage *Message): * * A frontend to the original routine. */ VOID GT_ReplyIMsg(struct IntuiMessage *Message) { /* Is this really a message? */ if(Message) { /* The following input event classes are likely to * affect a gadtools object. */ if(Message -> Class == IDCMP_GADGETUP || Message -> Class == IDCMP_GADGETDOWN || Message -> Class == IDCMP_MOUSEMOVE) { struct Gadget *Gadget; /* Take a look at the item attached. */ if(Gadget = (struct Gadget *)Message -> IAddress) { struct GadgetSupportInfo *Info = Gadget -> UserData; /* If it's really a gadget, does it * have an info structure attached? */ if(Info) { /* Does the data make sense? */ if(Info -> PointBack == Info && Info -> Gadget == Gadget) { LONG Value = (WORD)Message -> Code; /* Update the object information. */ switch(Info -> Kind) { case CHECKBOX_KIND: if(Gadget -> Flags & GFLG_SELECTED) Info -> Current = TRUE; else Info -> Current = FALSE; break; case CYCLE_KIND: Info -> Current = Message -> Code; break; case LISTVIEW_KIND: Info -> Current = Message -> Code; break; case MX_KIND: Info -> Current = Message -> Code; break; case SCROLLER_KIND: Info -> Current = Message -> Code; break; case SLIDER_KIND: if(Info -> Min >= 0 && Value < 0) Info -> Current = Message -> Code; else Info -> Current = Value; break; case PALETTE_KIND: Info -> Current = Message -> Code; break; default: break; } } } } } } /* Reply the message correctly. */ OldGT_ReplyIMsg(Message); } /* KeySelect(): * * Handles gadget keystroke activation. */ VOID KeySelect(struct Gadget **GadgetList,WORD Last,UBYTE Key,struct Window *Window,struct Gadget **Gadget,ULONG *Class,LONG *Code) { /* If an escape code comes in and the window does in * fact have a close gadget, return a close window * event. */ if(Key == '\033' && (Window -> Flags & WFLG_CLOSEGADGET)) *Class = IDCMP_CLOSEWINDOW; else { struct GadgetSupportInfo *Info; WORD i; BYTE Forward, GotIt = FALSE; /* Run down all the gadgets. */ for(i = 0 ; !GotIt && i <= Last ; i++) { /* Is this gadget enabled? */ if(!(GadgetList[i] -> Flags & GFLG_DISABLED)) { /* Does it have an info structure attached? */ if(Info = GadgetList[i] -> UserData) { /* Does it make sense? */ if(Info -> PointBack == Info && Info -> Gadget == GadgetList[i]) { /* Do the keys match? */ if(ToUpper(Info -> Key) == ToUpper(Key)) { /* Are we cycle forward * or backwards? */ if(ToUpper(Info -> Key) == Key) Forward = FALSE; else Forward = TRUE; /* Update the object information. */ switch(Info -> Kind) { case STRING_KIND: case INTEGER_KIND: ActivateGadget(ActiveGadget = GadgetList[i],Window,NULL); *Class = IDCMP_GADGETDOWN; *Code = 0; *Gadget = GadgetList[i]; GotIt = TRUE; break; case BUTTON_KIND: *Class = IDCMP_GADGETUP; *Code = 0; *Gadget = GadgetList[i]; GotIt = TRUE; break; case CHECKBOX_KIND: GT_SetGadgetAttrs(GadgetList[i],Window,NULL, GTCB_Checked, Info -> Current ? FALSE : TRUE, TAG_DONE); *Class = IDCMP_GADGETUP; *Code = Info -> Current; *Gadget = GadgetList[i]; GotIt = TRUE; break; case CYCLE_KIND: if(Forward) { GT_SetGadgetAttrs(GadgetList[i],Window,NULL, GTCY_Active, (Info -> Current == Info -> Max) ? 0 : Info -> Current + 1, TAG_DONE); } else { GT_SetGadgetAttrs(GadgetList[i],Window,NULL, GTCY_Active, Info -> Current ? Info -> Current - 1 : Info -> Max, TAG_DONE); } *Class = IDCMP_GADGETUP; *Code = Info -> Current; *Gadget = GadgetList[i]; GotIt = TRUE; break; case LISTVIEW_KIND: if(Forward) { if(Info -> Current == ~0) Info -> Current = -1; if(Info -> Current < Info -> Max) { if(Info -> ReadOnly) { GT_SetGadgetAttrs(GadgetList[i],Window,NULL, GTLV_Top, Info -> Current + 1, TAG_DONE); } else { GT_SetGadgetAttrs(GadgetList[i],Window,NULL, GTLV_Selected, Info -> Current + 1, GTLV_Top, Info -> Current + 1, TAG_DONE); } *Class = IDCMP_GADGETUP; *Code = Info -> Current; *Gadget = GadgetList[i]; } } else { if(Info -> Current == ~0) Info -> Current = Info -> Max + 1; if(Info -> Current > Info -> Min) { if(Info -> ReadOnly) { GT_SetGadgetAttrs(GadgetList[i],Window,NULL, GTLV_Top, Info -> Current - 1, TAG_DONE); } else { GT_SetGadgetAttrs(GadgetList[i],Window,NULL, GTLV_Selected, Info -> Current - 1, GTLV_Top, Info -> Current - 1, TAG_DONE); } *Class = IDCMP_GADGETUP; *Code = Info -> Current; *Gadget = GadgetList[i]; } } GotIt = TRUE; break; case MX_KIND: if(Forward) { if(Info -> Current < Info -> Max) { GT_SetGadgetAttrs(GadgetList[i],Window,NULL, GTMX_Active, *Code = Info -> Current + 1, TAG_DONE); *Class = IDCMP_GADGETUP; *Code = Info -> Current; *Gadget = GadgetList[i]; } } else { if(Info -> Current > Info -> Min) { GT_SetGadgetAttrs(GadgetList[i],Window,NULL, GTMX_Active, *Code = Info -> Current - 1, TAG_DONE); *Class = IDCMP_GADGETUP; *Code = Info -> Current; *Gadget = GadgetList[i]; } } GotIt = TRUE; break; case PALETTE_KIND: if(Forward) { GT_SetGadgetAttrs(GadgetList[i],Window,NULL, GTPA_Color, (Info -> Current == Info -> Max) ? 0 : Info -> Current + 1, TAG_DONE); } else { GT_SetGadgetAttrs(GadgetList[i],Window,NULL, GTPA_Color, Info -> Current ? Info -> Current - 1 : Info -> Max, TAG_DONE); } *Class = IDCMP_GADGETUP; *Code = Info -> Current; *Gadget = GadgetList[i]; GotIt = TRUE; break; case SCROLLER_KIND: if(Forward) { if(Info -> Current < Info -> Max) { GT_SetGadgetAttrs(GadgetList[i],Window,NULL, GTSC_Top, Info -> Current + 1, TAG_DONE); *Class = IDCMP_MOUSEMOVE; *Code = Info -> Current; *Gadget = GadgetList[i]; } } else { if(Info -> Current > Info -> Min) { GT_SetGadgetAttrs(GadgetList[i],Window,NULL, GTSC_Top, Info -> Current - 1, TAG_DONE); *Class = IDCMP_MOUSEMOVE; *Code = Info -> Current; *Gadget = GadgetList[i]; } } GotIt = TRUE; break; case SLIDER_KIND: if(Forward) { if(Info -> Current < Info -> Max) { GT_SetGadgetAttrs(GadgetList[i],Window,NULL, GTSL_Level, Info -> Current + 1, TAG_DONE); *Class = IDCMP_MOUSEMOVE; *Code = Info -> Current; *Gadget = GadgetList[i]; } } else { if(Info -> Current > Info -> Min) { GT_SetGadgetAttrs(GadgetList[i],Window,NULL, GTSL_Level, Info -> Current - 1, TAG_DONE); *Class = IDCMP_MOUSEMOVE; *Code = Info -> Current; *Gadget = GadgetList[i]; } } GotIt = TRUE; break; default: break; } } } } } } /* If no matching object was found, take a closer look at the types. */ if(!GotIt) { for(i = 0 ; i <= Last ; i++) { /* If it's a string object, activat it. */ if(!(GadgetList[i] -> Flags & GFLG_DISABLED) && (GadgetList[i] -> GadgetType & GTYP_GTYPEMASK) == GTYP_STRGADGET) { ActivateGadget(ActiveGadget = GadgetList[i],Window,NULL); *Class = IDCMP_GADGETDOWN; *Code = 0; *Gadget = GadgetList[i]; break; } } } } } /* SZ_ResetMaxWidth(): * * Reset maximum object width and return current maximum width. */ LONG SZ_ResetMaxWidth() { LONG Width = SZ_WidthMax; SZ_WidthMax = 0; return(Width); } /* SZ_UpdateMaxWidth(): * * Update current maximum object width. */ VOID __regargs SZ_UpdateMaxWidth(UBYTE Type,STRPTR Title,LONG Chars,STRPTR *Choices) { LONG Width = SZ_Width(Type,Title,Chars,Choices); if(Width > SZ_WidthMax) SZ_WidthMax = Width; } /* SZ_GetWindowWidth(): * * Get the current window width. */ LONG SZ_GetWindowWidth() { return(SZ_WindowWidth); } /* SZ_GetWindowHeight(): * * Get the current window height. */ LONG SZ_GetWindowHeight() { return(SZ_WindowHeight + SZ_Screen -> WBorBottom); } /* SZ_GetLeftEdge(): * * Get the current object left edge. */ LONG SZ_GetLeftEdge() { return(SZ_CurrentLeft); } /* SZ_GetTopEdge(): * * Get the current object top edge. */ LONG SZ_GetTopEdge() { return(SZ_CurrentTop); } /* SZ_SetTopEdge(LONG Top): * * Set the current object top edge. */ VOID __regargs SZ_SetTopEdge(LONG Top) { SZ_CurrentTop = Top; } /* SZ_SetLeftEdge(LONG Left): * * Set the current object left edge. */ VOID __regargs SZ_SetLeftEdge(LONG Left) { SZ_CurrentLeft = Left; } /* SZ_SetAbsoluteTop(LONG Top): * * Set new inner window top edge. */ VOID __regargs SZ_SetAbsoluteTop(LONG Top) { SZ_Top = Top; } /* SZ_SetAbsoluteLeft(LONG Left): * * Set new inner window left edge. */ VOID __regargs SZ_SetAbsoluteLeft(LONG Left) { SZ_Left = Left; } /* SZ_SetWidth(LONG Width): * * Set current object width. */ VOID __regargs SZ_SetWidth(LONG Width) { SZ_CurrentWidth = Width; } /* SZ_GetDimension(LONG *Width,LONG *Height): * * Get current window dimensions. */ VOID __regargs SZ_GetDimension(LONG *Width,LONG *Height) { *Width = SZ_WindowWidth; *Height = SZ_WindowHeight + SZ_Screen -> WBorBottom; } /* SZ_TextWidth(STRPTR String): * * Determine string width in pixels. */ LONG __regargs SZ_TextWidth(STRPTR String) { UBYTE TempString[256]; WORD i,j; for(i = j = 0 ; String[i] ; i++) { if(String[i] != '_') TempString[j++] = String[i]; } return(TextLength(SZ_RPort,TempString,j)); } /* SZ_AddLeftOffset(LONG Offset): * * Update current object left offset. */ VOID __regargs SZ_AddLeftOffset(LONG Offset) { SZ_CurrentLeft += Offset; } /* SZ_LeftOffsetN(LONG DataArray,...): * * Determine the maximum length of a number of * gadget labels (first, second, third item, -1 terminates * the array). */ LONG __stdargs SZ_LeftOffsetN(LONG DataArray,...) { extern STRPTR __regargs LocaleString(LONG ID); LONG *Data = &DataArray, Len, Max = 0; while(*Data != -1) { if((Len = SZ_TextWidth(LocaleString(*Data++))) > Max) Max = Len; } return(Max + INTERWIDTH); } /* SZ_LeftOffsetDelta(LONG From,LONG To): * * Determine the maximum length of a number of * gadget labels (given as first and last gadget). */ LONG __regargs SZ_LeftOffsetDelta(LONG From,LONG To) { extern STRPTR __regargs LocaleString(LONG ID); LONG i, Len, Max = 0; for(i = From ; i <= To ; i++) { if((Len = SZ_TextWidth(LocaleString(i))) > Max) Max = Len; } return(Max + INTERWIDTH); } /* SZ_SizeCleanup(): * * Free data allocated by SZ_SizeSetup(). */ VOID SZ_SizeCleanup() { if(SZ_TextFont) { CloseFont(SZ_TextFont); SZ_TextFont = NULL; } if(SZ_RPort) { FreeVec(SZ_RPort); SZ_RPort = NULL; } } /* SZ_SizeSetup(struct Screen *Screen,struct TextAttr *TextAttr,BYTE Title): * * Perform setups for gadget creation. */ BYTE __regargs SZ_SizeSetup(struct Screen *Screen,struct TextAttr *TextAttr,BYTE Title) { struct DrawInfo *DrawInfo; SZ_SizeCleanup(); if(DrawInfo = GetScreenDrawInfo(Screen)) { SZ_TextPen = DrawInfo -> dri_Pens[TEXTPEN]; FreeScreenDrawInfo(Screen,DrawInfo); } SZ_Screen = Screen; if(SZ_RPort = (struct RastPort *)AllocVec(sizeof(struct RastPort),MEMF_ANY | MEMF_CLEAR)) { InitRastPort(SZ_RPort); if(!TextAttr) TextAttr = Screen -> Font; if(DiskfontBase) SZ_TextFont = (struct TextFont *)OpenDiskFont(TextAttr); else SZ_TextFont = (struct TextFont *)OpenFont(TextAttr); if(SZ_TextFont) { InterWidth = INTERWIDTH; if(SZ_TextFont -> tf_YSize <= 8) InterHeight = 1; else InterHeight = SZ_TextFont -> tf_YSize / 4; SetFont(SZ_RPort,SZ_TextFont); if(Title) SZ_Top = Screen -> WBorTop + Screen -> Font -> ta_YSize + 1 + InterHeight; else SZ_Top = Screen -> WBorTop + InterHeight; SZ_Left = InterWidth; SZ_CurrentLeft = InterWidth; SZ_CurrentTop = SZ_Top; SZ_WindowWidth = 0; SZ_WindowHeight = 0; SZ_CurrentWidth = 0; SZ_MaxWidth = 0; return(TRUE); } } SZ_SizeCleanup(); return(FALSE); } /* SZ_Height(UBYTE Type,LONG Lines,BYTE Display): * * Determine the height of an object. */ LONG __regargs SZ_Height(UBYTE Type,LONG Lines,BYTE Display) { LONG Height = 0; switch(Type) { case LISTVIEW_KIND: Height = 4 + Lines * SZ_TextFont -> tf_YSize + 4; if(Display == SZLV_Display) Height += 2 + SZ_TextFont -> tf_YSize + 2; if(Display == SZLV_String) Height += 3 + SZ_TextFont -> tf_YSize + 3; break; case INTEGER_KIND: case STRING_KIND: Height = 3 + SZ_TextFont -> tf_YSize + 3; break; case CYCLE_KIND: case TEXT_KIND: case BUTTON_KIND: Height = 2 + SZ_TextFont -> tf_YSize + 2; break; case CHECKBOX_KIND: if(SZ_TextFont -> tf_YSize < 11) Height = 11; else Height = SZ_TextFont -> tf_YSize; break; case SLIDER_KIND: Height = 1 + SZ_TextFont -> tf_YSize + 1; break; case MX_KIND: Height = Lines * (SZ_TextFont -> tf_YSize + 1) - 1; break; case PALETTE_KIND: Height = 2 * SZ_TextFont -> tf_YSize; break; } return(Height); } /* SZ_Width(UBYTE Type,STRPTR Title,LONG Chars,STRPTR *Choices): * * Determine the width of an object. */ LONG __regargs SZ_Width(UBYTE Type,STRPTR Title,LONG Chars,STRPTR *Choices) { LONG Width = 0, Len,Max = 0,i; switch(Type) { case LISTVIEW_KIND: Width = (4 + Chars * SZ_TextFont -> tf_XSize + 4) + (2 + 2 * SZ_TextFont -> tf_XSize + 2) + 4; /* KLUDGE + 4 */ break; case TEXT_KIND: case BUTTON_KIND: if(Title) Width = 6 + SZ_TextWidth(Title) + 6; else Width = 6 + Chars * SZ_TextFont -> tf_XSize + 6; break; case SLIDER_KIND: case STRING_KIND: case INTEGER_KIND: Width = 6 + Chars * SZ_TextFont -> tf_XSize + 6; break; case CHECKBOX_KIND: if(SZ_TextFont -> tf_XSize < 13) Width = 26; else Width = 2 * SZ_TextFont -> tf_XSize; break; case CYCLE_KIND: if(Choices) { for(i = 0 ; Choices[i] ; i++) { if((Len = TextLength(SZ_RPort,Choices[i],strlen(Choices[i]))) > Max) Max = Len; } Width = 24 + Max + 4; } else Width = 24 + Chars * SZ_TextFont -> tf_XSize + 4; break; case MX_KIND: if(SZ_TextFont -> tf_XSize < 8) Width = 17; else Width = 2 * SZ_TextFont -> tf_XSize; break; } return(Width); } /* SZ_FreeBox(struct TextBox *Box): * * Free a text box. */ VOID __regargs SZ_FreeBox(struct TextBox *Box) { if(Box) { if(Box -> Text) { LONG i; for(i = 0 ; i < Box -> NumLines ; i++) { if(Box -> Text[i]) FreeVec(Box -> Text[i]); } FreeVec(Box -> Text); } if(Box -> Title) FreeVec(Box -> Title); FreeVec(Box); } } /* SZ_FreeBoxes(struct TextBox *FirstBox): * * Free a number of text boxes. */ VOID __regargs SZ_FreeBoxes(struct TextBox *FirstBox) { if(FirstBox) { struct TextBox *NextBox; do { NextBox = FirstBox -> NextBox; SZ_FreeBox(FirstBox); FirstBox = NextBox; } while(FirstBox); } } /* SZ_BoxWidth(LONG Chars): * * Determine the width of a text box. */ LONG __regargs SZ_BoxWidth(LONG Chars) { return(4 + SZ_TextFont -> tf_XSize * Chars + 4); } /* SZ_BoxHeight(LONG Lines): * * Determine the height of a text box. */ LONG __regargs SZ_BoxHeight(LONG Lines) { return(2 + SZ_TextFont -> tf_YSize * Lines + 2); } /* SZ_CreateTextBox(struct TextBox **FirstBox,...): * * Create a text box, this routine works similar * to the CreateGadget() frontend. */ struct TextBox * __stdargs SZ_CreateTextBox(struct TextBox **FirstBox,...) { va_list VarArgs; struct TagItem *TagList, *ThisTag; LONG Chars,Lines, Width, Height, Left = SZ_CurrentLeft; BYTE AutoWidth = FALSE, MoveDown = TRUE, SetLeft = FALSE, SetBelow = FALSE; struct TextBox *Box; LONG i; va_start(VarArgs,FirstBox); TagList = (struct TagItem *)VarArgs; if(ThisTag = FindTagItem(SZ_Lines,TagList)) Lines = (LONG)ThisTag -> ti_Data; else return(NULL); Height = 2 + SZ_TextFont -> tf_YSize * Lines + 2; if(ThisTag = FindTagItem(SZ_Chars,TagList)) Chars = (LONG)ThisTag -> ti_Data; else { if(ThisTag = FindTagItem(SZ_AutoWidth,TagList)) AutoWidth = ThisTag -> ti_Data; if(!AutoWidth) return(NULL); else Chars = (SZ_CurrentWidth - 8) / SZ_TextFont -> tf_XSize; } if(!(Box = (struct TextBox *)AllocVec(sizeof(struct TextBox),MEMF_ANY | MEMF_CLEAR))) return(NULL); if(ThisTag = FindTagItem(SZ_SetLeft,TagList)) SetLeft = ThisTag -> ti_Data; if(ThisTag = FindTagItem(SZ_SetBelow,TagList)) SetBelow = ThisTag -> ti_Data; if(ThisTag = FindTagItem(SZ_AlignBottom,TagList)) { if(ThisTag -> ti_Data) SZ_CurrentTop = SZ_WindowHeight; } if(ThisTag = FindTagItem(SZ_AlignExtra,TagList)) { if(ThisTag -> ti_Data) SZ_CurrentTop += InterHeight; } if(ThisTag = FindTagItem(SZ_NewColumn,TagList)) { if(ThisTag -> ti_Data) { SZ_CurrentTop = SZ_Top; Left = Left + SZ_MaxWidth + InterWidth; SZ_MaxWidth = 0; } } if(ThisTag = FindTagItem(SZ_AutoWidth,TagList)) AutoWidth = ThisTag -> ti_Data; if(!AutoWidth) Width = SZ_BoxWidth(Chars); else Width = SZ_CurrentWidth; if(ThisTag = FindTagItem(SZ_AlignLeft,TagList)) { if(ThisTag -> ti_Data) { Left = SZ_Left; MoveDown = FALSE; } } if(ThisTag = FindTagItem(SZ_AlignRight,TagList)) { if(ThisTag -> ti_Data) { Left = SZ_WindowWidth - INTERWIDTH - Width; MoveDown = FALSE; } } if(ThisTag = FindTagItem(SZ_AlignCentre,TagList)) { if(ThisTag -> ti_Data) { Left = (SZ_WindowWidth - Width) / 2; MoveDown = FALSE; } } if(ThisTag = FindTagItem(SZ_GroupCount,TagList)) { LONG Count = ThisTag -> ti_Data,Width = SZ_WindowWidth; if(ThisTag = FindTagItem(SZ_UseLeft,TagList)) { Width -= ThisTag -> ti_Data - InterWidth; SZ_GroupDelta = SZ_CurrentWidth + ((Width - 2 * InterWidth) - (Count * SZ_CurrentWidth)) / (Count - 1); SZ_GroupX = Left = ThisTag -> ti_Data; } else { SZ_GroupDelta = SZ_CurrentWidth + ((Width - 2 * InterWidth) - (Count * SZ_CurrentWidth)) / (Count - 1); SZ_GroupX = Left = SZ_Left; } MoveDown = FALSE; } else { if(ThisTag = FindTagItem(SZ_UseLeft,TagList)) Left = ThisTag -> ti_Data; } if(ThisTag = FindTagItem(SZ_GroupNext,TagList)) { if(ThisTag -> ti_Data) { SZ_GroupX += SZ_GroupDelta; Left = SZ_GroupX; MoveDown = FALSE; } } if(ThisTag = FindTagItem(SZ_UseTop,TagList)) SZ_CurrentTop = ThisTag -> ti_Data; Box -> Left = Left; Box -> Top = SZ_CurrentTop; Box -> Width = Width; Box -> Height = Height; Box -> LineWidth = Chars * SZ_TextFont -> tf_XSize; Box -> LineHeight = SZ_TextFont -> tf_YSize; Box -> NumChars = Chars; Box -> NumLines = Lines; Box -> TextPen = SZ_TextPen; if(!(Box -> Title = (STRPTR *)AllocVec(sizeof(STRPTR) * Lines,MEMF_ANY | MEMF_CLEAR))) { SZ_FreeBox(Box); return(NULL); } if(!(Box -> Text = (STRPTR *)AllocVec(sizeof(STRPTR) * Lines,MEMF_ANY | MEMF_CLEAR))) { SZ_FreeBox(Box); return(NULL); } for(i = 0 ; i < Lines ; i++) { if(!(Box -> Text[i] = (STRPTR)AllocVec(Chars + 1,MEMF_ANY | MEMF_CLEAR))) { SZ_FreeBox(Box); return(NULL); } } if(SetBelow) MoveDown = FALSE; if(MoveDown) { SZ_CurrentTop = SZ_CurrentTop + Height + InterHeight; if(SZ_CurrentTop > SZ_WindowHeight) SZ_WindowHeight = SZ_CurrentTop; } else { if(SZ_CurrentTop + Height + InterHeight > SZ_WindowHeight) SZ_WindowHeight = SZ_CurrentTop + Height + InterHeight; SZ_MaxWidth = 0; } if(Width > SZ_MaxWidth) SZ_MaxWidth = Width; if(Left + SZ_MaxWidth + INTERWIDTH > SZ_WindowWidth) SZ_WindowWidth = Left + SZ_MaxWidth + INTERWIDTH; if(!SetLeft) SZ_CurrentLeft = Left; if(!(*FirstBox)) *FirstBox = Box; else { struct TextBox *CurrentBox = *FirstBox; while(CurrentBox -> NextBox) CurrentBox = CurrentBox -> NextBox; CurrentBox -> NextBox = Box; } return(Box); } /* SZ_SetBoxTitles(struct TextBox *Box,STRPTR Array,...): * * Set the titles displayed in a text box. */ VOID __stdargs SZ_SetBoxTitles(struct TextBox *Box,STRPTR Array,...) { if(Box) { STRPTR *Data = &Array; LONG i = 0; while(*Data != NULL) { if(i < Box -> NumLines) Box -> Title[i++] = *Data; Data++; } } } /* SZ_PrintLine(): * * Print a string into a text box. */ VOID __stdargs SZ_PrintLine(struct RastPort *RPort,struct TextBox *Box,LONG Line,STRPTR String,...) { if(Box) { if(AttemptLockLayerRom(RPort -> Layer)) { BYTE FgPen = RPort -> FgPen,DrMd = RPort -> DrawMode; LONG Width,Len,Left = Box -> Left + 4,Top = Box -> Top + 2 + Line * Box -> LineHeight; va_list VarArgs; UBYTE Buffer[256]; va_start(VarArgs,String); VSPrintf(Buffer,String,VarArgs); va_end(VarArgs); if(DrMd != JAM2) SetDrMd(RPort,JAM2); SetAPen(RPort,Box -> TextPen); Len = strlen(Buffer); if(Len > Box -> NumChars) Len = Box -> NumChars; Width = TextLength(RPort,Buffer,Len); Move(RPort,Left,Top + RPort -> Font -> tf_Baseline); Text(RPort,Buffer,Len); if(Width != Box -> LineWidth) { if(FgPen != 0) SetAPen(RPort,0); RectFill(RPort,Left + Width,Top,Left + Box -> LineWidth - 1,Top + Box -> LineHeight - 1); } SetAPen(RPort,FgPen); if(DrMd != JAM2) SetDrMd(RPort,DrMd); if(String != Box -> Text[Line]) strcpy(Box -> Text[Line],Buffer); UnlockLayerRom(RPort -> Layer); } } } /* SZ_DrawBox(struct RastPort *RPort,struct TextBox *Box): * * (Re-)Draw a text box. */ VOID __regargs SZ_DrawBox(struct RastPort *RPort,struct TextBox *Box) { if(Box) { LONG LineY,i,Len,FgPen = RPort -> FgPen; DrawBevelBox(RPort,Box -> Left,Box -> Top,Box -> Width,Box -> Height, GT_VisualInfo, VisualInfo, GTBB_Recessed, TRUE, TAG_DONE); LineY = Box -> Top + 2 + RPort -> Font -> tf_Baseline; SetAPen(RPort,Box -> TextPen); for(i = 0 ; i < Box -> NumLines ; i++) { Len = strlen(Box -> Title[i]); Move(RPort,Box -> Left - INTERWIDTH - TextLength(RPort,Box -> Title[i],Len),LineY); Text(RPort,Box -> Title[i],Len); LineY += Box -> LineHeight; } SetAPen(RPort,FgPen); for(i = 0 ; i < Box -> NumLines ; i++) SZ_PrintLine(RPort,Box,i,Box -> Text[i]); } } /* SZ_DrawBoxes(struct RastPort *RPort,struct TextBox *FirstBox): * * (Re-)Draw a number of text boxes. */ VOID __regargs SZ_DrawBoxes(struct RastPort *RPort,struct TextBox *FirstBox) { do { SZ_DrawBox(RPort,FirstBox); FirstBox = FirstBox -> NextBox; } while(FirstBox); }