#include "demo.h"

/*****************************************************************************
** This is the Mousepower custom class, a sub class of Levelmeter.mui.
** It is quite simple and does nothing but add some input capabilities
** to its super class by implementing MUIM_HandleInput.
** Don't be afraid of writing sub classes!
******************************************************************************/

struct MousepowerData
{
	WORD Decrease;
	WORD MouseX;
	WORD MouseY;
	WORD Direction;
};

#define MUIA_Mousepower_Direction ((TAG_USER | ( 1 << 16)) | 0x0001)

SAVEDS ASM ULONG MousepowerDispatcher(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) Msg msg)
{
	switch (msg->MethodID)
	{
		case OM_NEW:
		{
			if (obj=(Object *)DoSuperMethodA(cl,obj,msg))
			{
				struct MousepowerData *data = INST_DATA(cl,obj);
				data->MouseX    = -1;
				data->Direction = GetTagData(MUIA_Mousepower_Direction,0,((struct opSet *)msg)->ops_AttrList);
				set(obj,MUIA_Numeric_Max,1000);
			}
			return((ULONG)obj);
		}
		break;

		case MUIM_Setup:
		{
			struct MousepowerData *data = INST_DATA(cl,obj);
			if (!DoSuperMethodA(cl,obj,msg))
				return(FALSE);
			data->MouseX = -1;
			set(obj,MUIA_Numeric_Max,1000);
			MUI_RequestIDCMP(obj,IDCMP_MOUSEMOVE|IDCMP_INTUITICKS|IDCMP_INACTIVEWINDOW);
			return(TRUE);
		}
		break;

		case MUIM_Cleanup:
		{
			MUI_RejectIDCMP(obj,IDCMP_MOUSEMOVE|IDCMP_INTUITICKS|IDCMP_INACTIVEWINDOW);
			return(DoSuperMethodA(cl,obj,msg));
		}
		break;

		case MUIM_HandleInput:
		{
			struct MUIP_HandleInput *m = (APTR)msg;
			struct MousepowerData *data = INST_DATA(cl,obj);

			if (m->imsg)
			{
				if (m->imsg->Class==IDCMP_MOUSEMOVE)
				{
					if (data->MouseX!=-1)
					{
						LONG delta;

						switch (data->Direction)
						{
							case 1 : delta = abs(data->MouseX - m->imsg->MouseX) * 2; break;
							case 2 : delta = abs(data->MouseY - m->imsg->MouseY) * 2; break;
							default: delta = abs(data->MouseX - m->imsg->MouseX) + abs(data->MouseY - m->imsg->MouseY); break;
						}
						if (data->Decrease>0) data->Decrease--;
						DoMethod(obj,MUIM_Numeric_Increase,delta/10);
					}
					data->MouseX = m->imsg->MouseX;
					data->MouseY = m->imsg->MouseY;
				}
				else if (m->imsg->Class==IDCMP_INTUITICKS)
				{
					DoMethod(obj,MUIM_Numeric_Decrease,data->Decrease*data->Decrease);
					if (data->Decrease<50) data->Decrease++;
				}
				else if (m->imsg->Class==IDCMP_INACTIVEWINDOW)
				{
					set(obj,MUIA_Numeric_Value,0);
				}
			}

			return(0);
		}
		break;
	}

	return(DoSuperMethodA(cl,obj,msg));
}



/*****************************************************************************
** This is the Rating custom class, a sub class of Slider.mui.
** It shows how to override the MUIM_Numeric_Stringify method
** to implement custom displays in a slider gadget. Nothing
** easier than that... :-)
******************************************************************************/

struct RatingData
{
	char buf[20];
};

SAVEDS ASM ULONG RatingDispatcher(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) Msg msg)
{
	if (msg->MethodID==MUIM_Numeric_Stringify)
	{
		struct RatingData *data = INST_DATA(cl,obj);
		struct MUIP_Numeric_Stringify *m = (APTR)msg;

		if (m->value==0)
		{
			strcpy(data->buf,"You're kidding!");
		}
		else if (m->value==100)
		{
			strcpy(data->buf,"It's magic!");
		}
		else
		{
			static const STRPTR ratings[] = { ":-((",":-(",":-|",":-)",":-))" };
			LONG r = DoMethod(obj,MUIM_Numeric_ValueToScale,0,sizeof(ratings)/sizeof(STRPTR)-1);
			sprintf(data->buf,"%3ld points. %s",m->value,(char *)ratings[r]);
		}
		return((ULONG)data->buf);
	}
	return(DoSuperMethodA(cl,obj,msg));
}



/*****************************************************************************
** A time slider custom class. Just like with the Rating class, we override
** the MUIM_Numeric_Stringify method. Wow... our classes get smaller and 
** smaller. This one only has about 10 lines of C code. :-)
** Note that we can use this TimeDispatcher as subclass of any of
** MUI's numeric classes. In Slidorama, we create a Timebutton class
** from MUIC_Numericbutton and Timeslider class for MUIC_Slider with
** the same dispatcher function.
******************************************************************************/

struct TimeData
{
	char buf[16];
};

SAVEDS ASM ULONG TimeDispatcher(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) Msg msg)
{
	if (msg->MethodID==MUIM_Numeric_Stringify)
	{
		struct TimeData *data = INST_DATA(cl,obj);
		struct MUIP_Numeric_Stringify *m = (APTR)msg;
		sprintf(data->buf,"%02ld:%02ld",m->value/60,m->value%60);
		return((ULONG)data->buf);
	}
	return(DoSuperMethodA(cl,obj,msg));
}



/*****************************************************************************
** Main Program
******************************************************************************/

static struct MUI_CustomClass *MousepowerClass;
static struct MUI_CustomClass *RatingClass;
static struct MUI_CustomClass *TimebuttonClass;
static struct MUI_CustomClass *TimesliderClass;

static VOID CleanupClasses(VOID)
{
	if (MousepowerClass) MUI_DeleteCustomClass(MousepowerClass);
	if (RatingClass    ) MUI_DeleteCustomClass(RatingClass);
	if (TimebuttonClass) MUI_DeleteCustomClass(TimebuttonClass);
	if (TimesliderClass    ) MUI_DeleteCustomClass(TimesliderClass);
}

static BOOL SetupClasses(VOID)
{
	MousepowerClass = MUI_CreateCustomClass(NULL,MUIC_Levelmeter,NULL,sizeof(struct MousepowerData),MousepowerDispatcher);
	RatingClass     = MUI_CreateCustomClass(NULL,MUIC_Slider,NULL,sizeof(struct RatingData),RatingDispatcher);
	TimesliderClass = MUI_CreateCustomClass(NULL,MUIC_Slider,NULL,sizeof(struct TimeData),TimeDispatcher);
	TimebuttonClass = MUI_CreateCustomClass(NULL,MUIC_Numericbutton,NULL,sizeof(struct TimeData),TimeDispatcher);

	if (MousepowerClass && RatingClass && TimebuttonClass && TimesliderClass)
		return(TRUE);

	CleanupClasses();
	return(FALSE);
}

int main(int argc,char *argv[])
{
	APTR app,window,knob[3*4];
	int k=0;

	init();

	if (!SetupClasses())
		fail(NULL,"Could not create custom classes.");

	app = ApplicationObject,
		MUIA_Application_Title      , "Slidorama",
		MUIA_Application_Version    , "$VER: Slidorama 14.16 (21.02.96)",
		MUIA_Application_Copyright  , "©1992-95, Stefan Stuntz",
		MUIA_Application_Author     , "Stefan Stuntz",
		MUIA_Application_Description, "Show different kinds of sliders",
		MUIA_Application_Base       , "SLIDORAMA",

		SubWindow, window = WindowObject,
			MUIA_Window_Title, "Slidorama",
			MUIA_Window_ID   , MAKE_ID('S','L','I','D'),

			WindowContents, VGroup,

				Child, HGroup,

					Child, VGroup, GroupSpacing(0), GroupFrameT("Knobs"),
						Child, VSpace(0),
						Child, ColGroup(6),
							GroupSpacing(0),
							Child, VSpace(0),
							Child, HSpace(4),
							Child, CLabel("1"),
							Child, CLabel("2"),
							Child, CLabel("3"),
							Child, CLabel("4"),
							Child, VSpace(2),
							Child, VSpace(2),
							Child, VSpace(2),
							Child, VSpace(2),
							Child, VSpace(2),
							Child, VSpace(2),
							Child, Label("Volume:"),
							Child, HSpace(4),
							Child, knob[k++] = KnobObject, MUIA_Numeric_Max, 64, MUIA_Numeric_Default, 64, End,
							Child, knob[k++] = KnobObject, MUIA_Numeric_Max, 64, MUIA_Numeric_Default, 64, End,
							Child, knob[k++] = KnobObject, MUIA_Numeric_Max, 64, MUIA_Numeric_Default, 64, End,
							Child, knob[k++] = KnobObject, MUIA_Numeric_Max, 64, MUIA_Numeric_Default, 64, End,
							Child, Label("Bass:"),
							Child, HSpace(4),
							Child, knob[k++] = KnobObject, MUIA_Numeric_Min, -100, MUIA_Numeric_Max, 100, End,
							Child, knob[k++] = KnobObject, MUIA_Numeric_Min, -100, MUIA_Numeric_Max, 100, End,
							Child, knob[k++] = KnobObject, MUIA_Numeric_Min, -100, MUIA_Numeric_Max, 100, End,
							Child, knob[k++] = KnobObject, MUIA_Numeric_Min, -100, MUIA_Numeric_Max, 100, End,
							Child, Label("Treble:"),
							Child, HSpace(4),
							Child, knob[k++] = KnobObject, MUIA_Numeric_Min, -100, MUIA_Numeric_Max, 100, End,
							Child, knob[k++] = KnobObject, MUIA_Numeric_Min, -100, MUIA_Numeric_Max, 100, End,
							Child, knob[k++] = KnobObject, MUIA_Numeric_Min, -100, MUIA_Numeric_Max, 100, End,
							Child, knob[k  ] = KnobObject, MUIA_Numeric_Min, -100, MUIA_Numeric_Max, 100, End,
							End,
						Child, VSpace(0),
						End,

					Child, VGroup,
						Child, VGroup, GroupFrameT("Levelmeter Displays"),
							Child, VSpace(0),
							Child, HGroup,
								Child, HSpace(0),
								Child, NewObject(MousepowerClass->mcc_Class,0,MUIA_Mousepower_Direction,1,MUIA_Levelmeter_Label,"Horizontal",TAG_DONE),
								Child, HSpace(0),
								Child, NewObject(MousepowerClass->mcc_Class,0,MUIA_Mousepower_Direction,2,MUIA_Levelmeter_Label,"Vertical"  ,TAG_DONE),
								Child, HSpace(0),
								Child, NewObject(MousepowerClass->mcc_Class,0,MUIA_Mousepower_Direction,0,MUIA_Levelmeter_Label,"Total"     ,TAG_DONE),
								Child, HSpace(0),
								End,
							Child, VSpace(0),
							End,
						Child, VGroup, GroupFrameT("Numeric Buttons"),
							Child, VSpace(0),
							Child, HGroup, GroupSpacing(0),
								Child, HSpace(0),
								Child, ColGroup(4), MUIA_Group_VertSpacing, 1,
									Child, VSpace(0),
									Child, CLabel("Left"),
									Child, CLabel("Right"),
									Child, CLabel("SPL"),
									Child, Label1("Low:"),
									Child, MUI_MakeObject(MUIO_NumericButton,NULL,0,100,"%3ld %%"),
									Child, MUI_MakeObject(MUIO_NumericButton,NULL,0,100,"%3ld %%"),
									Child, MUI_MakeObject(MUIO_NumericButton,NULL,30,99,"%2ld dB"),
									Child, Label1("Mid:"),
									Child, MUI_MakeObject(MUIO_NumericButton,NULL,0,100,"%3ld %%"),
									Child, MUI_MakeObject(MUIO_NumericButton,NULL,0,100,"%3ld %%"),
									Child, MUI_MakeObject(MUIO_NumericButton,NULL,30,99,"%2ld dB"),
									Child, Label1("High:"),
									Child, MUI_MakeObject(MUIO_NumericButton,NULL,0,100,"%3ld %%"),
									Child, MUI_MakeObject(MUIO_NumericButton,NULL,0,100,"%3ld %%"),
									Child, MUI_MakeObject(MUIO_NumericButton,NULL,30,99,"%2ld dB"),
									End,
								Child, HSpace(0),
								End,
							Child, VSpace(0),
							End,
						End,

					End,

				Child, VSpace(4),

				Child, ColGroup(2),
					Child, Label("Slidorama Rating:"),
					Child, NewObject(RatingClass->mcc_Class,0,
						MUIA_Numeric_Value,50,
						TAG_DONE),
					End,
				End,
			End,
		End;

	if (!app)
		fail(app,"Failed to create Application.");



	DoMethod(window,MUIM_Notify,MUIA_Window_CloseRequest,TRUE,
		app,2,MUIM_Application_ReturnID,MUIV_Application_ReturnID_Quit);

	DoMethod(window,MUIM_Window_SetCycleChain,
		knob[0*4+0],knob[0*4+1],knob[0*4+2],knob[0*4+3],
		knob[1*4+0],knob[1*4+1],knob[1*4+2],knob[1*4+3],
		knob[2*4+0],knob[2*4+1],knob[2*4+2],knob[2*4+3],
		NULL);


/*
** This is the ideal input loop for an object oriented MUI application.
** Everything is encapsulated in classes, no return ids need to be used,
** we just check if the program shall terminate.
** Note that MUIM_Application_NewInput expects sigs to contain the result
** from Wait() (or 0). This makes the input loop significantly faster.
*/

	set(window,MUIA_Window_Open,TRUE);

	{
		ULONG sigs = 0;

		while (DoMethod(app,MUIM_Application_NewInput,&sigs) != MUIV_Application_ReturnID_Quit)
		{
			if (sigs)
			{
				sigs = Wait(sigs | SIGBREAKF_CTRL_C);
				if (sigs & SIGBREAKF_CTRL_C) break;
			}
		}
	}

	set(window,MUIA_Window_Open,FALSE);


/*
** Shut down...
*/

	MUI_DisposeObject(app);
	CleanupClasses();
	fail(NULL,NULL);
}
