/*
 *  RTGGadgets  V1.2
 *
 *
 *  A package to use gadget-like input elements on RTG screens
 *
 *  Copyright © 1996 by Thomas and Hans-Joerg Frieden
 *  Written by Thomas and Hans-Joerg Frieden
 *
 *  This software may be freely distributed. The copyright remains with
 *  the copyright holders. For further information, see legal.doc
 *  In no way may this software be modified without permission of the
 *  copyright holders.
 *
 *  This software is provided "as is", and may only be used at your own risk.
 *  The copyright holder and/or the authors can not be held responible for any
 *  damage the usage of this software may cause. To put it in other words, we are not
 *  responisble if your cat dies while using this software.
 *
 *  Version         Comment
 *  --------------------------------------------------------------
 *  0.1             Initial Version without custom functions
 *  1.0             Custom functions inserted
 *  1.1             Mouse handling moved to custom input handler, cleanups
 *  1.2             Added keypress gadget activation
 *
 */

#include <clib/console_protos.h>
#include "global.h"
#include "RTGGadgets.h"

extern struct RTGMasterBase *RTGMasterBase;
extern struct Library *UtilityBase;

struct MsgPort *RTGInputMsgPort;
struct IOStdReq *RTGInputIO;
struct Interrupt InputHandler;
RTGInpRec RTGInputRecord;
struct Device *ConsoleDevice;
struct IOStdReq RTGConsoleIO;
struct InputEvent RTGIe;


struct TagItem mtag[] = {
    grd_MouseX,         0,
    grd_MouseY,         0,
    TAG_DONE,           0
};

struct TagItem ctag[] = {
    grd_ColorSpace, 0,
    grd_BytesPerRow,0,
    TAG_DONE,       0
};


/****** RTGGadgets/CreateRTGGList  ******************************************
*
*   NAME   
*       CreateRTGGList  --  Create and initialize RTGGList header
*
*   SYNOPSIS
*       GList = CreateRTGGList( screen, flags)
*
*       struct RTGGList *CreateRTGGList( struct RTGScreen *, int);
*
*   FUNCTION
*       Allocate RTGGList header and initialize it.
*
*   INPUTS
*       screen = Pointer to an initialized RTGScreen
*       flags  = flags for this screens gadget list
*
*   RESULT
*       A pointer to the RTGGList structure, or zero if there was an error
*
*****************************************************************************
*/

struct RTGGList *CreateRTGGList(struct RtgScreen *scr, int flags) {

    struct RTGGList *createme;

    if (!scr) return(NULL);

    createme = malloc(sizeof(struct RTGGList));

    if (!createme) return(NULL);

    createme->gl_First  = NULL;
    createme->gl_Hit    = NULL;
    createme->gl_Selected = NULL;
    createme->gl_Screen = scr;
    createme->gl_Buffer = 0;
    createme->gl_Mode   = TRUE;
    createme->gl_Flags  = flags;
    createme->gl_Reset  = NULL;

    return(createme);
}

/****** RTGGadgets/CreateRTGGadgetA ******************************************
*
*   NAME
*       CreateRTGGadgetA -- Allocate and initialize an RTG Gadget
*
*   SYNOPSIS
*       result = CreateRTGGadgetA(list, id, tags);
*
*       int CreateRTGGadgetA(struct RTGGList, int, struct TagItem *);
*
*   FUNCTION
*       Create an RTG Gadget with id in list list
*
*   INPUTS
*       list - pointer to an RTG gadget list
*       id   - Unique identification number of this gadget
*       tags - pointer to a tag list. The tagitems are as follows:
*
*           RGADT_LeftEdge      Left edge of gadget (x coordinate)
*           RGADT_TopEdge       Top edge of gadget (y coordinate)
*           RGADT_Width         Width of gadget
*           RGADT_Height        Height of gadget
*           RGADT_Flags         Flags. See below.
*           RGADT_HitTest       Custom function for hit testing
*           RGADT_HitRender     Custom function for rendering hit gadget
*           RGADT_DownRender    Custom function for rendering pressed gadget
*           RGADT_UpRender      Custom function for rendering depressed gadget
*           RGADT_Force         Force this gadet id. Error if already present
*           RGADT_HitPen        Set the hit pen for the standard renderer
*           RGADT_UpPen         Set up pen
*           RGADT_DownPen       Set down pen
*           RGADT_Key           key to activate gadget
*
*
*       The flags field can have the following values:
*
*           RGADF_HITHILITE     The gadget is hihglited when the mouse is
*                               positioned above it.
*
*   RESULT
*       The result is the gadgets id, or -1 if ther was an error.
*       An error also occurs if the gadget`s id was already in use while
*       setting the RGADT_Force tag to TRUE.
*
*   NOTE
*       The key to activate the gadget is the latin 1 representation, not
*       the rawkey code.
*
*****************************************************************************
*/


int CreateRTGGadgetA(struct RTGGList *list, int id,  struct TagItem *tags) {

    struct TagItem *tag;
    struct TagItem *tstate;
    struct RTGGadget *do_me;
    struct RTGGadget *akt;
    BOOL force = TRUE;
    BOOL fail = FALSE;

    if (!list) return(-1);

    GetRtgScreenData(list->gl_Screen, ctag);

    do_me = malloc(sizeof(struct RTGGadget));

    if (!do_me) return(-1);

    do_me->rg_ID        = id;       //  Default values
    do_me->rg_Left      = 0;
    do_me->rg_Top       = 0;
    do_me->rg_Width     = 8;
    do_me->rg_Height    = 8;
    do_me->rg_Flags     = 0;
    do_me->rg_HitTest   = NULL;
    do_me->rg_HitRender = NULL;
    do_me->rg_DownRender= NULL;
    do_me->rg_UpRender  = NULL;
    do_me->rg_UserData  = NULL;
    do_me->rg_ExtHandle = NULL;
    do_me->rg_Key       = 0;

    switch (ctag[0].ti_Data) {
        case grd_Palette:
            do_me->rg_HitPen    =   1;
            do_me->rg_DownPen   =   2;
            do_me->rg_UpPen     =   3;
            break;
        default:
            do_me->rg_HitPen    =   0x0f00;
            do_me->rg_DownPen   =   0x00f0;
            do_me->rg_UpPen     =   0x0fff;
            break;
    }

    //  Now parse tag list

    tstate = tags;

    while ( tag = NextTagItem(&tstate)) {
        switch (tag->ti_Tag) {
            case RGADT_LeftEdge:
                do_me->rg_Left = (int)(tag->ti_Data);
                break;
            case RGADT_TopEdge:
                do_me->rg_Top = (int)(tag->ti_Data);
                break;
            case RGADT_Width:
                do_me->rg_Width = (int)(tag->ti_Data);
                break;
            case RGADT_Height:
                do_me->rg_Height = (int)(tag->ti_Data);
                break;
            case RGADT_Flags:
                do_me->rg_Flags = (int)(tag->ti_Data);
                break;
            case RGADT_HitTest:
                do_me->rg_HitTest = (void *)(tag->ti_Data);
                break;
            case RGADT_HitRender:
                do_me->rg_HitRender = (void *)(tag->ti_Data);
                printf("Read: %x, Inserted: %x\n",tag->ti_Data, do_me->rg_HitRender);
                break;
            case RGADT_DownRender:
                do_me->rg_DownRender = (void *)(tag->ti_Data);
                break;
            case RGADT_UpRender:
                do_me->rg_UpRender = (void *)(tag->ti_Data);
                break;
            case RGADT_Force:
                force = (BOOL)(tag->ti_Data);
                break;
            case RGADT_HitPen:
                do_me->rg_HitPen = (int)(tag->ti_Data);
                break;
            case RGADT_UpPen:
                do_me->rg_UpPen = (int)(tag->ti_Data);
                break;
            case RGADT_DownPen:
                do_me->rg_DownPen = (int)(tag->ti_Data);
                break;
            case RGADT_UserData:
                do_me->rg_UserData = (APTR)(tag->ti_Data);
                break;
            case RGADT_Key:
                do_me->rg_Key = (char)(tag->ti_Data);
                break;
        }   // switch
    }   // while

    if (!list->gl_First) {
        list->gl_First = do_me;
        do_me->rg_Next = NULL;
        return(id);
    }

    akt = list->gl_First;                   //  Scan the gadget list
    while (akt->rg_Next) {
        if (akt->rg_ID == id) {             //  id already in use
            if (force) {
                fail = TRUE;
                break;
            } else
                id = INT_MAX;
        }
        if (akt->rg_Next->rg_ID > id)       //  insert here
            break;
        akt = akt->rg_Next;
    }

    if (fail) {                             //  We already have this id
        free(do_me);                        //  and want to enforce it, so
        return(-1);                         //  we fail :(
    }

    if (id == INT_MAX) {                    //  if id was already in use
        id = akt->rg_ID + 1;                //  use the next free one
        do_me->rg_ID = id;
    }


    do_me->rg_Next = akt->rg_Next;          //  Put it into the list
    akt->rg_Next = do_me;

    return(id);
}


int CreateRTGGadget(struct RTGGList *list, int id,  Tag tags, ...) {
    return (CreateRTGGadgetA(list, id, (struct TagItem *)&tags));
}


/****** RTGGadgets/DeleteRTGGadget ******************************************
*
*   NAME   
*       DeleteRTGGadget -- Delete an RTG gadget from the list
*
*   SYNOPSIS
*       id = DeleteRTGGadget(list, id);
*
*       int DeleteRTGGadget(struct RTGGList, int);
*
*   FUNCTION
*       Delete RTG gadget from list.
*
*   INPUTS
*       list - pointer to a struct RTGGList
*       id   - identification number of the gadget to be deleted
*
*   RESULT
*       The result is the id of the removed gadget.
*
*****************************************************************************
*/


int DeleteRTGGadget(struct RTGGList *list, int id) {

    struct RTGGadget *akt;
    struct RTGGadget *killme;

    if (!list) return(-1);

    if (!list->gl_First)                            //  List is empty
        return(-1);

    akt = list->gl_First;                           //  Search in list
    if (akt->rg_ID != id) {
        while(akt->rg_Next) {
            if (akt->rg_Next->rg_ID == id)
                break;
            akt = akt->rg_Next;
        }
    }

    if (!akt->rg_Next)                              //  Not found
        return(-1);

    killme = akt->rg_Next;
    akt->rg_Next = akt->rg_Next->rg_Next;
    free(killme);

    return(id);
}


/****** RTGGadgets/RTGGHitTest ******************************************
*
*   NAME   
*       RTGGHitTest -- Test gadget hitbox against mouse coordinates
*
*   SYNOPSIS
*       RTGGHitTest(akt, x, y);
*
*       int RTGGHitTest(struct RTGGadget *, int, int);
*
*   FUNCTION
*       This function tests if the point given by x,y is inside the gadget`s
*       hit box.
*       This function is called automatically by RefreshRTGGList.
*       It can be replaced by a user-defined function for more complicated
*       or special cases.
*
*   INPUTS
*       akt - Gadget to test
*       x   - x coordinate of test point
*       y   - y coordinate of test point
*
*   RESULT
*       0 - no hit
*       1 - hit
*
*   NOTES
*
*
*****************************************************************************
*
*/


int RTGGHitTest(struct RTGGadget *akt, int x, int y) {

    if (!akt) return(0);

    if (akt->rg_HitTest) {
        return(akt->rg_HitTest(akt, x, y));
    }

    if (x <= akt->rg_Left) return(0);
    if (x >= akt->rg_Left + akt->rg_Width) return(0);
    if (y <= akt->rg_Top)  return(0);
    if (y >= akt->rg_Top + akt->rg_Height) return(0);
    return(1);
}


/*
 *
 *  DrawRTGBox
 *
 */

void DrawRTGBox(struct RtgScreen *scr, APTR badr, int x, int y, int w, int h, char c) {

    int i;
    int bpr;
    char *l1, *l2;

    GetRtgScreenData(scr, ctag);

    bpr = ctag[1].ti_Data;

    l1 = (char *)(y * bpr + x + (char *)badr);
    l2 = (char *)((y + h) * bpr + x+ (char *)badr) ;

    for(i = 0; i < w; i++) {
        *l1 = c;
        *l2 = c;
        l1++; l2 ++;
    }

    l1 = (char *)(y * bpr + x + (char *)badr);
    l2 = (char *)(y * bpr + x + w + (char *)badr);

    for(i = 0; i <= h; i++) {
        *l1 = c;
        *l2 = c;
        l1 += bpr;
        l2 += bpr;
    }
}


/****** RTGGadget/RTGGHitRender ******************************************
*
*   NAME   
*       RTGGHitRender -- Render gadget in hit position
*
*   SYNOPSIS
*       RTGGHitRender(list, akt);
*
*       RTGGHitRender(struct RTGGlist *, struct RTGGadget *);
*
*   FUNCTION
*       Render gadget in hit position (i.e. pointer is over gadget)
*       This function is called by RefreshRTGGList.
*       It can be replaced by a custom function.
*
*   INPUTS
*       list - pointer ot gadget list
*       akt  - pointer to gadget
*
*
*****************************************************************************
*
*/


void RTGGHitRender(struct RTGGList *list, struct RTGGadget *akt) {

    APTR badr;
    int x,y,w,h;

    if (!list) return;

    if (!(akt->rg_Flags & RGADF_HITHILITE)) return;

    if (akt->rg_HitRender) {
        akt->rg_HitRender(list, akt);
        return;
    }

    GetRtgScreenData(list->gl_Screen, ctag);
    badr = GetBufAdr(list->gl_Screen, list->gl_Buffer);

    x = akt->rg_Left;
    y = akt->rg_Top;
    w = akt->rg_Width;
    h = akt->rg_Height;

    if (ctag[0].ti_Data == grd_Palette) {
/*        DrawRtgLine(list->gl_Screen, badr, akt->rg_HitPen, x, y, x+w, y);
        DrawRtgLine(list->gl_Screen, badr, akt->rg_HitPen, x, y+h, x+w, y+h);
        DrawRtgLine(list->gl_Screen, badr, akt->rg_HitPen, x, y, x, y+h);
        DrawRtgLine(list->gl_Screen, badr, akt->rg_HitPen, x+w, y, x+w, y+h);*/
        DrawRTGBox(list->gl_Screen, badr, x, y, w, h, akt->rg_HitPen);
    } else {
        DrawRtgLineRGB(list->gl_Screen, badr, akt->rg_HitPen, x, y, x+w, y);
        DrawRtgLineRGB(list->gl_Screen, badr, akt->rg_HitPen, x, y+h, x+w, y+h);
        DrawRtgLineRGB(list->gl_Screen, badr, akt->rg_HitPen, x, y, x, y+h);
        DrawRtgLineRGB(list->gl_Screen, badr, akt->rg_HitPen, x+w, y, x+w, y+h);
    }
}


/****** RTGGadget/RTGGDownRender ******************************************
*
*   NAME
*       RTGGDownRender -- Render gadget in down position
*
*   SYNOPSIS
*       RTGGDownRender(list, akt);
*
*       RTGGDownRender(struct RTGGlist *, struct RTGGadget *);
*
*   FUNCTION
*       Render gadget in down position (i.e. pointer is over gadget and
*       button pressed).
*       This function is called by RefreshRTGGList.
*       It can be replaced by a custom function.
*
*   INPUTS
*       list - pointer ot gadget list
*       akt  - pointer to gadget
*
*
*****************************************************************************
*
*/

void RTGGDownRender(struct RTGGList *list, struct RTGGadget *akt) {

    APTR badr;
    int x,y,w,h;

    if (!list) return;

    if (akt->rg_DownRender) {
        akt->rg_DownRender(list, akt);
        return;
    }

    GetRtgScreenData(list->gl_Screen, ctag);
    badr = GetBufAdr(list->gl_Screen, list->gl_Buffer);

    x = akt->rg_Left;
    y = akt->rg_Top;
    w = akt->rg_Width;
    h = akt->rg_Height;

    if (ctag[0].ti_Data == grd_Palette) {
/*        DrawRtgLine(list->gl_Screen, badr, akt->rg_DownPen, x, y, x+w, y);
        DrawRtgLine(list->gl_Screen, badr, akt->rg_DownPen, x, y+h, x+w, y+h);
        DrawRtgLine(list->gl_Screen, badr, akt->rg_DownPen, x, y, x, y+h);
        DrawRtgLine(list->gl_Screen, badr, akt->rg_DownPen, x+w, y, x+w, y+h);*/
        DrawRTGBox(list->gl_Screen, badr, x, y, w, h, akt->rg_DownPen);
    } else {
        DrawRtgLineRGB(list->gl_Screen, badr, akt->rg_DownPen, x, y, x+w, y);
        DrawRtgLineRGB(list->gl_Screen, badr, akt->rg_DownPen, x, y+h, x+w, y+h);
        DrawRtgLineRGB(list->gl_Screen, badr, akt->rg_DownPen, x, y, x, y+h);
        DrawRtgLineRGB(list->gl_Screen, badr, akt->rg_DownPen, x+w, y, x+w, y+h);
    }
}


/****** RTGGadget/RTGGUpRender ******************************************
*
*   NAME
*       RTGGUpRender -- Render gadget in up position
*
*   SYNOPSIS
*       RTGGUpRender(list, akt);
*
*       RTGGUpRender(struct RTGGlist *, struct RTGGadget *);
*
*   FUNCTION
*       Render gadget in down position (i.e. pointer is not over gadget).
*       This function is called by RefreshRTGGList.
*       It can be replaced by a custom function.
*
*   INPUTS
*       list - pointer ot gadget list
*       akt  - pointer to gadget
*
*****************************************************************************
*
*/


void RTGGUpRender(struct RTGGList *list, struct RTGGadget *akt) {

    APTR badr;
    int x,y,w,h;

    if (!list) return;

    if (akt->rg_UpRender) {
        akt->rg_UpRender(list, akt);
        return;
    }

    GetRtgScreenData(list->gl_Screen, ctag);
    badr = GetBufAdr(list->gl_Screen, list->gl_Buffer);

    x = akt->rg_Left;
    y = akt->rg_Top;
    w = akt->rg_Width;
    h = akt->rg_Height;

    if (ctag[0].ti_Data == grd_Palette) {
/*        DrawRtgLine(list->gl_Screen, badr, akt->rg_UpPen, x, y, x+w, y);
        DrawRtgLine(list->gl_Screen, badr, akt->rg_UpPen, x, y+h, x+w, y+h);
        DrawRtgLine(list->gl_Screen, badr, akt->rg_UpPen, x, y, x, y+h);
        DrawRtgLine(list->gl_Screen, badr, akt->rg_UpPen, x+w, y, x+w, y+h);*/
        DrawRTGBox(list->gl_Screen, badr, x, y, w, h, akt->rg_UpPen);
    } else {
        DrawRtgLineRGB(list->gl_Screen, badr, akt->rg_UpPen, x, y, x+w, y);
        DrawRtgLineRGB(list->gl_Screen, badr, akt->rg_UpPen, x, y+h, x+w, y+h);
        DrawRtgLineRGB(list->gl_Screen, badr, akt->rg_UpPen, x, y, x, y+h);
        DrawRtgLineRGB(list->gl_Screen, badr, akt->rg_UpPen, x+w, y, x+w, y+h);
    }
}

/****** RTGGadgets/RefreshRTGGList ******************************************
*
*   NAME   
*       RefreshRTGGList -- Refresh and redraw list of gadgets
*
*   SYNOPSIS
*       RefreshRTGGList(list)
*
*       void RefreshRTGGList(struct RTGGList *);
*
*   FUNCTION
*       Refresh the state of the gadgets in list list and redraw everything.
*
*   INPUTS
*       list - pointer to an RTGGList
*
*****************************************************************************
*/


void RefreshRTGGList(struct RTGGList *list) {

    struct RTGGadget *akt;
    int x,y;
    BYTE buffer[10];

    if (!list) return;

    GetRtgScreenData(list->gl_Screen, mtag);        //  Read mouse

    x = mtag[0].ti_Data;
    y = mtag[1].ti_Data;


    if (!list->gl_First) return;

    if (list->gl_Reset) {
        RTGGUpRender(list, list->gl_Reset);
        list->gl_Reset = NULL;
    }

    if (RTGInputRecord.LastKey != 0) {              //  Key was pressed
        RTGIe.ie_NextEvent = NULL;
        RTGIe.ie_Class = IECLASS_RAWKEY;
        RTGIe.ie_Code = RTGInputRecord.LastKey;
        RTGIe.ie_Qualifier = 0;
        RTGIe.ie_position.ie_addr = NULL;
        RawKeyConvert(&RTGIe, buffer, 10, NULL);
        RTGInputRecord.LastKey = 0;

        for(akt = list->gl_First; akt; akt = akt->rg_Next) {
            if (akt->rg_Key == buffer[0]) {
                list->gl_Selected = akt;
                RTGGDownRender(list, akt);
                list->gl_Reset = akt;
            }
        }
    }

    for(akt = list->gl_First; akt; akt = akt->rg_Next)  //  Find akt
        if (RTGGHitTest(akt, x, y)){
            break;
        }

    if (akt) {
        if (list->gl_Mode) {                            //  UpMode
            if (akt != list->gl_Hit) {
                if (list->gl_Hit) RTGGUpRender(list, list->gl_Hit);
                RTGGHitRender(list, akt);
                list->gl_Hit = akt;
            }
        } else {                                        //  DownMode
            if ((list->gl_Hit) && RTGGHitTest(list->gl_Hit, x, y)) {
                RTGGDownRender(list, list->gl_Hit);
            } else {
                if (list->gl_Hit) RTGGUpRender(list, list->gl_Hit);
            }
        }
    } else {
        if (list->gl_Hit) RTGGUpRender(list, list->gl_Hit);
        if (list->gl_Mode) list->gl_Hit = 0;
    }

    if (RTGInputRecord.MK1) {
        list->gl_Mode = FALSE;          //  DownMode
        list->gl_Hit = akt;
        RTGInputRecord.MK1 = 0;
    }
    if (RTGInputRecord.UK1) {
        list->gl_Mode = TRUE;       //  UpMode
        RTGInputRecord.UK1 = 0;
        if (akt == list->gl_Hit) {
            list->gl_Selected = list->gl_Hit;
            list->gl_Hit = NULL;
            if (list->gl_Selected) RTGGUpRender(list, list->gl_Selected);
        }
    }
}


/****** RTGGadgets/DeleteRTGGList ******************************************
*
*   NAME   
*       DeleteRTGGList -- Delete a list of RTG gadgets
*
*   SYNOPSIS
*       success = DeleteRTGGList(list, force);
*
*       BOOL DeleteRTGGList(struct RTGGList *, BOOL);
*
*   FUNCTION
*       Delete a list of RTG gadgets, including the list header.
*
*   INPUTS
*       list - a pointer to the RTGGList structure to be deleted
*       force - a boolean flag to force the list to be deleted, even if there
*               are gadgets left in it.
*
*   RESULT
*       a boolean value of TRUE indicates successful deletion.
*
*****************************************************************************
*/


BOOL DeleteRTGGList(struct RTGGList *list, BOOL force) {

    struct RTGGadget *akt;
    struct RTGGadget *next;

    if (!list) return(TRUE);

    if ((!force) && (list->gl_First)) return(FALSE);    //  not enforced, and still gadgets in list

    akt = list->gl_First;

    while (akt) {
        next = akt->rg_Next;
        free(akt);
        akt = next;
    }

    free(list);

    return(TRUE);
}


/****** RTGGadgets/RTGGAddIPH ******************************************
*
*   NAME   
*       RTGGAddIPH -- Add Input handler to system
*
*   SYNOPSIS
*       RTGGAddIPH();
*
*       void RTGGAddIPH(void);
*
*   FUNCTION
*       Install input handler
*
*   INPUTS
*
*   RESULT
*
*****************************************************************************
*/


void RTGGAddIPH(void) {
    extern void HandlerCode();

    InputHandler.is_Code = HandlerCode;
    InputHandler.is_Data = &RTGInputRecord;
    InputHandler.is_Node.ln_Pri=100;
    InputHandler.is_Node.ln_Name="mygame input handler";

    RTGInputIO->io_Data = (APTR)&InputHandler;
    RTGInputIO->io_Command = IND_ADDHANDLER;
    DoIO((struct IORequest *)RTGInputIO);

    RTGInputRecord.MK1 = 0;
    RTGInputRecord.UK1 = 0;
    RTGInputRecord.LastKey = 0;

}


/****** RTGGadgets/RTGGRemIPH ******************************************
*
*   NAME
*       RTGGRemIPH -- Remove input handler
*
*   SYNOPSIS
*       RTGGRemIPH();
*
*       void RTGGRemIPH(void);
*
*   FUNCTION
*       Install input handler
*
*   INPUTS
*
*   RESULT
*
*****************************************************************************
*/


void RTGGRemIPH(void) {
    RTGInputIO->io_Data = (APTR)&InputHandler;
    RTGInputIO->io_Command = IND_REMHANDLER;
    DoIO((struct IORequest *)RTGInputIO);
}


/****** RTGGadgets/RTGGOpenInput ******************************************
*
*   NAME
*       RTGGOpenInput -- Open input device
*
*   SYNOPSIS
*       RTGGOpenInput;
*
*       void RTGGOpenInput(void);
*
*   FUNCTION
*       Open input device
*
*   INPUTS
*
*   RESULT
*
*****************************************************************************
*/


BOOL RTGGOpenInput(void) {

    BYTE error;

    RTGInputMsgPort = CreatePort(0L, 0L);
    if (!RTGInputMsgPort)
        return(FALSE);

    RTGInputIO = (struct IOStdReq *) CreateExtIO(RTGInputMsgPort, sizeof(struct IOStdReq));
    if (!RTGInputIO) {
        DeletePort(RTGInputMsgPort);
        return(FALSE);
    }

    error = OpenDevice((STRPTR)"input.device", 0L, (struct IORequest *)RTGInputIO, 0);
    if (error) {
        DeleteExtIO((struct IORequest *)RTGInputIO);
        DeletePort(RTGInputMsgPort);
        return(FALSE);
    }

    error = OpenDevice("console.device", -1, (struct IORequest *)&RTGConsoleIO, 0L);
    if (error) {
        CloseDevice((struct IORequest *)RTGInputIO);
        DeleteExtIO((struct IORequest *)RTGInputIO);
        DeletePort(RTGInputMsgPort);
        return(FALSE);
    }

    ConsoleDevice = (struct Device *)RTGConsoleIO.io_Device;

    return(TRUE);
}


/****** RTGGadgets/RTGGCloseInput ******************************************
*
*   NAME
*       RTGGCloseInput -- Close input device
*
*   SYNOPSIS
*       RTGGCloseInput;
*
*       void RTGGCloseInput(void);
*
*   FUNCTION
*       Close input device
*
*   INPUTS
*
*   RESULT
*
*****************************************************************************
*/


void RTGGCloseInput(void) {

    if (RTGInputIO) {
        if ((BOOL)CheckIO((struct IORequest *)RTGInputIO) == TRUE) {
            AbortIO((struct IORequest *)RTGInputIO);
            WaitIO((struct IORequest *)RTGInputIO);
        }
        CloseDevice((struct IORequest *)RTGInputIO);
        DeleteExtIO((struct IORequest *)RTGInputIO);
        DeletePort(RTGInputMsgPort);
    }

    if (ConsoleDevice) {
        CloseDevice((struct IORequest *)&RTGConsoleIO);
        ConsoleDevice = NULL;
    }
}


/****** RTGGadgets/DrawRTGGList ******************************************
*
*   NAME   
*       DrawRTGGList -- Draw a list of RTG Gadgets in their "up" position
*
*   SYNOPSIS
*       DrawRTGGList(list);
*
*       DrawRTGGList(struct RTGGList *);
*
*   FUNCTION
*       Draw a list of RTG Gadgets in their "up" position :)
*
*   INPUTS
*       list - a pointer to an RTGGList structure
*
*   RESULT
*
*****************************************************************************
*/

void DrawRTGGList(struct RTGGList *list) {

    struct RTGGadget *akt;

    if (!list) return;

    for(akt = list->gl_First; akt; akt = akt->rg_Next)
        RTGGUpRender(list, akt);

}

