/* strhooks.c -- string gadget hooks	*/
/* WARNING: This file contains "callback" functions.
 * You must disable stack checking for them to work:
 * 		"LC -v strhooks"
 */

/*
Copyright (c) 1989 Commodore-Amiga, Inc.

Executables based on this information may be used in software
for Commodore Amiga computers. All other rights reserved.
This information is provided "as is"; no warranties are made.
All use is at your own risk, and no liability or responsibility
is assumed.
*/

#include <exec/types.h>
#include <devices/inputevent.h>
#include <utility/hooks.h>
#include <intuition/sghooks.h>

#include <clib/intuition_protos.h>
#include <clib/diskfont_protos.h>
#include <clib/exec_protos.h>

#include <string.h>
#include <stdlib.h>

#include "strgad.h"

struct Hook	tabhook;
struct Hook	cyclehook;

/* forward in this file	*/
void	tabh(struct Hook	*hook,struct SGWork	*sgw,ULONG		*msg);
void	cycleh(struct Hook	*hook,struct SGWork	*sgw,ULONG		*msg);

#define TABSCAN	(0x42)

#define SHIFTY (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)

#define D( x )	;	/* debugging: on 'x', off ';'	*/

__saveds ULONG hookEntry( register __a0 struct Hook *hookptr, register __a2 void	*object, register __a1 void	*message )
{
	return ( (*hookptr->h_SubEntry)( hookptr, object, message ) );
}

void initHook(struct Hook	*hook,void	(*ccode)(struct Hook	*hook,struct SGWork	*sgw,ULONG		*msg))
{
    hook->h_Entry = (ULONG (*)())hookEntry;
    hook->h_SubEntry = (ULONG (*)()) ccode;
    hook->h_Data = 0;		/* I don't use it		*/
}

void initMyHooks(void)
{
    initHook( &tabhook, tabh );
    initHook( &cyclehook, cycleh );
}

/*
 * This is a function which converts register-parameter
 * hook calling convention into standard C conventions.
 * It only works with Lattice C 5.0+
 * 
 * Without the fancy __asm stuff, you'd probably need to
 * write this in assembler.
 *
 * You could conceivably declare all your C hook functions
 * this way, and eliminate the middleman (you'd initialize
 * the h_Entry field to your C function's address, and not
 * bother with the h_SubEntry field).
 *
 * This is nice and easy, though, and since we're using the
 * small data model, using a single interface routine like this
 * (which does the necessary __saveds), it might
 * actually turn out to be smaller to use a single entry point
 * like this rather than declaring each of many hooks __saveds.
 */



void tabh(struct Hook	*hook,struct SGWork	*sgw,ULONG		*msg)
{
    D( kprintf("tabh: sgw: %lx\n", sgw ) );

    if ( ( *msg == SGH_KEY ) && ( sgw->IEvent->ie_Code == TABSCAN ) )
    {
	sgw->Code = (sgw->IEvent->ie_Qualifier & SHIFTY)?
	    MYCODEBACKTAB: MYCODETAB;
	sgw->Actions |= SGA_END;
	sgw->Actions &= ~SGA_USE;
    }
}

UBYTE	*choices[] = {
    (UBYTE *) "choice 1",
    (UBYTE *) "choice 2",
    (UBYTE *) "choice 3",
    (UBYTE *) "choice 4",
    (UBYTE *) "choice 5",
    (UBYTE *) "choice 6"
};

#define NUMCHOICES	((sizeof (choices))/sizeof (UBYTE *))
#define UPARROW		(0x4c)
#define DOWNARROW	(0x4d)

void cycleh(struct Hook	*hook,struct SGWork	*sgw,ULONG		*msg)
{
    static int	choice = 0;

    D( kprintf("cycleh: %lx, sgw: %lx\n", sgw ) );

    if ( *msg != SGH_KEY ) return;

    switch ( sgw->IEvent->ie_Code )
    {
    case TABSCAN:
	sgw->Code = (sgw->IEvent->ie_Qualifier & SHIFTY)?
	    MYCODEBACKTAB: MYCODETAB;
	sgw->Actions |= SGA_END;
	sgw->Actions &= ~SGA_USE;
	break;

    case UPARROW:
	D( kprintf("cycle hook (up), previous choice %ld\n", choice ));
	sgw->WorkBuffer = choices[ choice = (choice + 1)%NUMCHOICES ];
	sgw->NumChars = strlen( sgw->WorkBuffer );
	D( kprintf("new choice: %ld <%s>\n",choice, sgw->WorkBuffer ) );
	break;

    case DOWNARROW:
	D( kprintf("cycle hook (down), previous choice %ld\n", choice ));
	sgw->WorkBuffer = choices[choice=(choice+(NUMCHOICES-1))%NUMCHOICES];
	sgw->NumChars = strlen( sgw->WorkBuffer );
	D( kprintf("new choice: %ld <%s>\n",choice, sgw->WorkBuffer ) );
	break;
    }
}

