/*
** MUI Helper Header of MadCat!
*/

#ifndef AMSTER_MUI_H
#define AMSTER_MUI_H

#include <proto/exec.h>
#include <proto/utility.h>
#include <proto/intuition.h>
#include <libraries/mui.h>
#include <proto/muimaster.h>
#include <clib/alib_protos.h>

#include "compiler.h"

#ifdef __MORPHOS__
#undef MUI_NewObject
#define DoMethod(MyObject, tags...) \
	({ULONG _tags[] = { tags }; DoMethodA((MyObject), (APTR)_tags);})
#define DoSuperMethod(MyClass, MyObject, tags...) \
	({ULONG _tags[] = { tags }; DoSuperMethodA((MyClass), (MyObject), (APTR)_tags);})
#define CoerceMethod(MyClass, MyObject, tags...) \
	({ULONG _tags[] = { tags }; CoerceMethodA((MyClass), (MyObject), (APTR)_tags);})
#endif	/* __MORPHOS__ */

#define MUIM_Window_Cleanup       0x8042ab26 /* Custom Class */ /* V18 */
#define MUIM_Window_Setup         0x8042c34c /* Custom Class */ /* V18 */

#define MAKE_ID(a,b,c,d) ((ULONG) (a)<<24 | (ULONG) (b)<<16 | (ULONG) (c)<<8 | (ULONG) (d))

#ifdef __MORPHOS__
static void putChar_gate(void);
static struct EmulLibEntry putChar =
{
	TRAP_LIB, 0, (void (*)(void)) putChar_gate
};
#else
void SAVEDS ASM putChar(REG(a0, struct Hook *hook), REG(a1, char c), REG(a2, struct Locale *locale));
#endif

#ifdef __MORPHOS__
ULONG DoSuperNew(struct IClass *cl, Object *obj, ...);
#else
ULONG __stdargs DoSuperNew(struct IClass *cl, Object *obj, ULONG tag1, ...);
#endif

typedef struct muimsg_struct {
	ULONG MethodID;
	ULONG *arg1;
	ULONG *arg2;
	ULONG *arg3;
	ULONG *arg4;
} *muimsg;

Object *maketmenu(const UBYTE *msg);
Object *makemenu(const UBYTE *msg);
Object *maketoggle(const UBYTE *msg, Object **tog);
void SPrintF(char *outstr, char *fmtstr, ...);

typedef struct
{
	char *supername;
	int datasize;
	APTR dispatcher;
	struct MUI_CustomClass **ptr;
} muiclass;

int mui_classes_setup(muiclass mcl[]);
void mui_classes_cleanup(muiclass mcl[]);



/* Following macros makes your hooks compatible with sas/c, gcc, and gcc-morphos */

#ifdef __MORPHOS__
#define MUI_HOOK_DECL(x,y,z) struct EmulLibEntry x
#define MUI_HOOK(x,y,z) \
	static ULONG SAVEDS x ## _gate(void); \
	static ULONG x ## _gate2(struct Hook *hook, y , z ); \
	struct EmulLibEntry x = { \
	TRAP_LIB, 0, (void (*)(void)) x ## _gate }; \
	static ULONG SAVEDS x ## _gate(void) { \
	return ( x ## _gate2((void *)REG_A0, (void *)REG_A2, (void *)REG_A1)); } \
	static ULONG x ## _gate2(struct Hook *hook, y , z )
#define MUI_HOOK_STATIC(x,y,z) \
	static ULONG SAVEDS x ## _gate(void); \
	static ULONG x ## _gate2(struct Hook *hook, y , z ); \
	static struct EmulLibEntry x = { \
	TRAP_LIB, 0, (void (*)(void)) x ## _gate }; \
	static ULONG SAVEDS x ## _gate(void) { \
	return ( x ## _gate2((void *)REG_A0, (void *)REG_A2, (void *)REG_A1)); } \
	static ULONG x ## _gate2(struct Hook *hook, y , z )

#define MUI_DISPATCH_DECL(x) struct EmulLibEntry x
#define MUI_DISPATCH(x) \
	static ULONG SAVEDS x ## _gate(void); \
	static ULONG x ## _gate2(struct IClass *cl, Object *obj, Msg msg); \
	struct EmulLibEntry x = { \
	TRAP_LIB, 0, (void (*)(void)) x ## _gate }; \
	static ULONG SAVEDS x ## _gate(void) { \
	return ( x ## _gate2((void *)REG_A0, (void *)REG_A2, (void *)REG_A1)); } \
	static ULONG x ## _gate2(struct IClass *cl, Object *obj, Msg msg)
#define MUI_DISPATCH_STATIC(x) \
	static ULONG SAVEDS x ## _gate(void); \
	static ULONG x ## _gate2(struct IClass *cl, Object *obj, Msg msg); \
	static struct EmulLibEntry x = { \
	TRAP_LIB, 0, (void (*)(void)) x ## _gate }; \
	static ULONG SAVEDS x ## _gate(void) { \
	return ( x ## _gate2((void *)REG_A0, (void *)REG_A2, (void *)REG_A1)); } \
	static ULONG x ## _gate2(struct IClass *cl, Object *obj, Msg msg)

#define MUI_LIST_DISP_DECL(x,y) struct EmulLibEntry x
#define MUI_LIST_DISP(x,y) \
	static ULONG SAVEDS x ## _gate(void); \
	static ULONG x ## _gate2(char **array, y ); \
	struct EmulLibEntry x = { \
	TRAP_LIB, 0, (void (*)(void)) x ## _gate }; \
	static ULONG SAVEDS x ## _gate(void) { \
	return ( x ## _gate2((void *)REG_A2, (void *)REG_A1)); } \
	static ULONG x ## _gate2(char **array, y )
#define MUI_LIST_DISP_STATIC(x,y) \
	static ULONG SAVEDS x ## _gate(void); \
	static ULONG x ## _gate2(char **array, y ); \
	static struct EmulLibEntry x = { \
	TRAP_LIB, 0, (void (*)(void)) x ## _gate }; \
	static ULONG SAVEDS x ## _gate(void) { \
	return ( x ## _gate2((void *)REG_A2, (void *)REG_A1)); } \
	static ULONG x ## _gate2(char **array, y )

#define MUI_LIST_CONS_DECL(x,y) struct EmulLibEntry x
#define MUI_LIST_CONS(x,y) \
	static ULONG SAVEDS x ## _gate(void); \
	static ULONG x ## _gate2(APTR pool, y ); \
	struct EmulLibEntry x = { \
	TRAP_LIB, 0, (void (*)(void)) x ## _gate }; \
	static ULONG SAVEDS x ## _gate(void) { \
	return ( x ## _gate2((void *)REG_A2, (void *)REG_A1)); } \
	static ULONG x ## _gate2(APTR pool, y )
#define MUI_LIST_CONS_STATIC(x,y) \
	static ULONG SAVEDS x ## _gate(void); \
	static ULONG x ## _gate2(APTR pool, y ); \
	static struct EmulLibEntry x = { \
	TRAP_LIB, 0, (void (*)(void)) x ## _gate }; \
	static ULONG SAVEDS x ## _gate(void) { \
	return ( x ## _gate2((void *)REG_A2, (void *)REG_A1)); } \
	static ULONG x ## _gate2(APTR pool, y )

#define MUI_LIST_DEST_DECL(x,y) struct EmulLibEntry x
#define MUI_LIST_DEST(x,y) \
	static ULONG SAVEDS x ## _gate(void); \
	static ULONG x ## _gate2(APTR pool, y ); \
	struct EmulLibEntry x = { \
	TRAP_LIB, 0, (void (*)(void)) x ## _gate }; \
	static ULONG SAVEDS x ## _gate(void) { \
	return ( x ## _gate2((void *)REG_A2, (void *)REG_A1)); } \
	static ULONG x ## _gate2(APTR pool, y )
#define MUI_LIST_DEST_STATIC(x,y) \
	static ULONG SAVEDS x ## _gate(void); \
	static ULONG x ## _gate2(APTR pool, y ); \
	static struct EmulLibEntry x = { \
	TRAP_LIB, 0, (void (*)(void)) x ## _gate }; \
	static ULONG SAVEDS x ## _gate(void) { \
	return ( x ## _gate2((void *)REG_A2, (void *)REG_A1)); } \
	static ULONG x ## _gate2(APTR pool, y )

#define MUI_LIST_COMP_DECL(x,y,z) struct EmulLibEntry x
#define MUI_LIST_COMP(x,y,z) \
	static ULONG SAVEDS x ## _gate(void); \
	static ULONG x ## _gate2( y , z ); \
	struct EmulLibEntry x = { \
	TRAP_LIB, 0, (void (*)(void)) x ## _gate }; \
	static ULONG SAVEDS x ## _gate(void) { \
	return ( x ## _gate2((void *)REG_A1, (void *)REG_A2)); } \
	static ULONG x ## _gate2( y , z )
#define MUI_LIST_COMP_STATIC(x,y,z) \
	static ULONG SAVEDS x ## _gate(void); \
	static ULONG x ## _gate2( y , z ); \
	static struct EmulLibEntry x = { \
	TRAP_LIB, 0, (void (*)(void)) x ## _gate }; \
	static ULONG SAVEDS x ## _gate(void) { \
	return ( x ## _gate2((void *)REG_A1, (void *)REG_A2)); } \
	static ULONG x ## _gate2( y , z )

#define MUI_NLIST_COMP_DECL(x) struct EmulLibEntry x
#define MUI_NLIST_COMP(x) \
	static ULONG SAVEDS x ## _gate(void); \
	static ULONG x ## _gate2(struct Hook *hook, Object *obj, struct NList_CompareMessage *ncm); \
	struct EmulLibEntry x = { \
	TRAP_LIB, 0, (void (*)(void)) x ## _gate }; \
	static ULONG SAVEDS x ## _gate(void) { \
	return ( x ## _gate2((void *)REG_A0, (void *)REG_A2, (void *)REG_A1)); } \
	static ULONG x ## _gate2(struct Hook *hook, Object *obj, struct NList_CompareMessage *ncm)

#define MUI_APPMSG_DECL(x) struct EmulLibEntry x
#define MUI_APPMSG(x) \
	static ULONG SAVEDS x ## _gate(void); \
	static ULONG x ## _gate2(APTR obj, struct AppMessage **lala); \
	struct EmulLibEntry x = { \
	TRAP_LIB, 0, (void (*)(void)) x ## _gate }; \
	static ULONG SAVEDS x ## _gate(void) { \
	return ( x ## _gate2((void *)REG_A2, (void *)REG_A1)); } \
	static ULONG x ## _gate2(APTR obj, struct AppMessage **appmsg)

#else
#define MUI_HOOK_DECL(x,y,z) ULONG SAVEDS ASM x (REG(a0,struct Hook *hook), REG(a2, y ), REG(a1, z ))
#define MUI_HOOK(x,y,z) ULONG SAVEDS ASM x (REG(a0,struct Hook *hook), REG(a2, y ), REG(a1, z ))
#define MUI_HOOK_STATIC(x,y,z) static ULONG SAVEDS ASM x (REG(a0,struct Hook *hook), REG(a2, y ), REG(a1, z ))

#define MUI_DISPATCH_DECL(x) ULONG SAVEDS ASM x (REG(a0,struct IClass *cl), REG(a2,Object *obj), REG(a1,Msg msg))
#define MUI_DISPATCH(x) ULONG SAVEDS ASM x (REG(a0,struct IClass *cl), REG(a2,Object *obj), REG(a1,Msg msg))

#define MUI_LIST_DISP_DECL(x,y) ULONG SAVEDS ASM x (REG(a2,char **array), REG(a1, y ))
#define MUI_LIST_DISP(x,y) ULONG SAVEDS ASM x (REG(a2,char **array), REG(a1, y ))
#define MUI_LIST_DISP_STATIC(x,y) static ULONG SAVEDS ASM x (REG(a2,char **array), REG(a1, y ))

#define MUI_LIST_CONS_DECL(x,y) ULONG SAVEDS ASM x (REG(a2,APTR pool), REG(a1, y ))
#define MUI_LIST_CONS(x,y) ULONG SAVEDS ASM x (REG(a2,APTR pool), REG(a1, y ))
#define MUI_LIST_CONS_STATIC(x,y) static ULONG SAVEDS ASM x (REG(a2,APTR pool), REG(a1, y ))

#define MUI_LIST_DEST_DECL(x,y) ULONG SAVEDS ASM x (REG(a2,APTR pool), REG(a1, y ))
#define MUI_LIST_DEST(x,y) ULONG SAVEDS ASM x (REG(a2,APTR pool), REG(a1, y ))
#define MUI_LIST_DEST_STATIC(x,y) static ULONG SAVEDS ASM x (REG(a2,APTR pool), REG(a1, y ))

#define MUI_LIST_COMP_DECL(x,y,z) LONG SAVEDS ASM x (REG(a1, y ), REG(a2, z ))
#define MUI_LIST_COMP(x,y,z) LONG SAVEDS ASM x (REG(a1, y ), REG(a2, z ))
#define MUI_LIST_COMP_STATIC(x,y,z) static LONG SAVEDS ASM x (REG(a1, y ), REG(a2, z ))

#define MUI_NLIST_COMP_DECL(x) ULONG SAVEDS ASM x (REG(a0,struct Hook *hook), REG(a2,Object *obj), REG(a1, struct NList_CompareMessage *ncm))
#define MUI_NLIST_COMP(x) ULONG SAVEDS ASM x (REG(a0,struct Hook *hook), REG(a2,Object *obj), REG(a1, struct NList_CompareMessage *ncm))

#define MUI_APPMSG_DECL(x) ULONG SAVEDS ASM x (REG(a2,APTR obj), REG(a1,struct AppMessage **appmsg))
#define MUI_APPMSG(x) ULONG SAVEDS ASM x (REG(a2,APTR obj), REG(a1,struct AppMessage **appmsg))
#endif



#endif	/* AMSTER_MUI_H */
