/*
 *  evdpanel.c - evdPanel class
 *  Copyright (C) 1997 Aki Laukkanen
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software Foundation,
 *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <string.h>
#include "prefs.h"
#include "macros.h"

/*
 * methods
 */

#define MUIM_evdPanel_GetState (TAGBASE_AMLAUKKA+0x0021)
#define MUIM_evdPanel_SetState (TAGBASE_AMLAUKKA+0x0022)
#define MUIM_evdPanel_New      (TAGBASE_AMLAUKKA+0x0023)
#define MUIM_evdPanel_Edit     (TAGBASE_AMLAUKKA+0x0024)
#define MUIM_evdPanel_Delete   (TAGBASE_AMLAUKKA+0x0025)
#define MUIM_evdPanel_Change   (TAGBASE_AMLAUKKA+0x0026)

/*
 * attributes
 */

/*
 * internal structures
 */

struct MUIP_evdPanel_Prefs
{
	ULONG   MethodID;
	char*   name;               /* file name */
};

/*
 * function prototypes
 */

static ULONG evdPanel_NEW(struct IClass*, Object*, struct opSet*);
static ULONG evdPanel_Load(struct IClass*, Object*, struct MUIP_evdPanel_Prefs*);
static ULONG evdPanel_Save(struct IClass*, Object*, struct MUIP_evdPanel_Prefs*);
static ULONG evdPanel_GetState(struct IClass*, Object*, Msg);
static ULONG evdPanel_SetState(struct IClass*, Object*, Msg);
static ULONG evdPanel_New(struct IClass*, Object*, Msg);
static ULONG evdPanel_Edit(struct IClass*, Object*, Msg);
static ULONG evdPanel_Delete(struct IClass*, Object*, Msg);
static ULONG evdPanel_Change(struct IClass*, Object*, Msg);
static ULONG evdPanel_Finish(struct IClass*, Object*, struct MUIP_evdPanel_Finish *);
static ULONG evdPanel_CloseWindows(struct IClass*, Object*, Msg);

static struct paletteEntry* REGARGS pal_list_construct_hook(REG(a2, APTR), REG(a1, char*));
static void  REGARGS pal_list_destruct_hook(  REG(a2, APTR), REG(a1, struct paletteEntry*));
static LONG  REGARGS pal_list_display_hook(   REG(a2, char**), REG(a1, struct paletteEntry*));
static BOOL pal_list_change_entry( struct paletteEntry*, char*);

/*
 * global symbols
 */

/*
 *  SYNOPSIS
 *      evdPanel_Finish(class, object, msg)
 *
 *  FUNCTION
 *      Function gets a palette window as a parameter. This window is
 *      searched from the palette list and the appropriate pointer
 *      is set to NULL. Window will be closed and removed from the
 *      app's member list. Finally it will be disposed.
 */

static ULONG
evdPanel_Finish(struct IClass* cl, Object* obj, struct MUIP_evdPanel_Finish* msg)
{
	int i;
	struct paletteEntry* pal = NULL;
	struct evdPanelData* data = INST_DATA(cl, obj);

	for ( i = 0 ;; i++ )
	{
		DoMethod(data->LV_Palettes, MUIM_List_GetEntry, i, &pal);
		if (!pal)
			return 0;

		if (pal->palWindow == msg->win)
			break;
	}

	DoMethod(data->LV_Palettes, MUIM_List_Redraw, i);
	pal->palWindow = NULL;

	set(msg->win, MUIA_Window_Open, FALSE);
	DoMethod((Object*)xget(obj, MUIA_ApplicationObject), OM_REMMEMBER, msg->win);
	MUI_DisposeObject(msg->win);

	return 0;
}

/*
 *  SYNOPSIS
 *      evdPanel_CloseWindows(class, obj, msg)
 *
 *  FUNCTION
 *      The list of palettes is iterated and each open window
 *      is closed.
 */

static ULONG
evdPanel_CloseWindows(struct IClass* cl, Object* obj, Msg msg)
{
	int i;
	struct paletteEntry* pal;
	struct evdPanelData* data = INST_DATA(cl, obj);

	for ( i = 0 ;; i++ )
	{
		DoMethod(data->LV_Palettes, MUIM_List_GetEntry, i, &pal);
		if (!pal)
			break;

		if (pal->palWindow)
			DoMethod(obj, MUIM_evdPanel_Finish, pal->palWindow);
			/* FIXME: not very efficient */
	}
	return 0;
}

/*
 *  SYNOPSIS
 *      evdPanel_GetState(class, object, message)
 *
 *  FUNCTION
 *      Updates the internal state of the object by checking
 *      the state of the radio buttons and sliders.
 */

static ULONG
evdPanel_GetState(struct IClass* cl, Object* obj, Msg msg)
{
	struct evdPanelData* data = INST_DATA(cl, obj);

	data->refreshrate = xget(data->SL_RRate, MUIA_Slider_Level);
	data->bblank = getbool(data->CM_BBlank);
	data->own_refresh = getbool(data->CM_OwnRefr);
	data->copyback_buffer = !getbool(data->CM_FCached);
	data->imprecise_bitplanes = getbool(data->CM_CImpres);
	data->numpals = xget(data->LV_Palettes, MUIA_List_Entries);
	data->usedpal = xget(data->LV_Palettes, MUIA_List_Active);

	return 0;
}

/*
 *  SYNOPSIS
 *      evdPanel_SetState(class, object, message)
 *
 *  FUNCTION
 *      Updates the state of window components by checking
 *      the internal state of the object. This function is
 *      called for example after loading a new set of preferences.
 */

static ULONG
evdPanel_SetState(struct IClass* cl, Object* obj, Msg msg)
{
	struct paletteEntry* pal;
	struct evdPanelData* data = INST_DATA(cl, obj);

	if (xget(data->LV_Palettes, MUIA_List_Entries))
	{
		set(data->BT_Edit, MUIA_Disabled, FALSE);
		set(data->BT_Delete, MUIA_Disabled, FALSE);
		set(data->ST_PaletteName, MUIA_Disabled, FALSE);
		DoMethod(data->LV_Palettes, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &pal);
		set(data->ST_PaletteName, MUIA_String_Contents, pal->name);
	}
	else
	{
		set(data->BT_Edit, MUIA_Disabled, TRUE);
		set(data->BT_Delete, MUIA_Disabled, TRUE);
		set(data->ST_PaletteName, MUIA_String_Contents, "");
		set(data->ST_PaletteName, MUIA_Disabled, TRUE);
	}

	set(data->SL_RRate,   MUIA_Slider_Level, (ULONG)data->refreshrate);
	set(data->CM_BBlank,  MUIA_Selected,     (ULONG)data->bblank);
	set(data->CM_OwnRefr, MUIA_Selected,     (ULONG)data->own_refresh);
	set(data->CM_FCached, MUIA_Selected,     (ULONG)!data->copyback_buffer);
	set(data->CM_CImpres, MUIA_Selected,     (ULONG)data->imprecise_bitplanes);

	set(data->SL_RRate, MUIA_Disabled, !(ULONG)data->own_refresh);

	return 0;
}

/*
 *  SYNOPSIS
 *      evdPanel_Change(class, object, message)
 *
 *  FUNCTION
 *      Changes the name of the active listview entry.
 */

static ULONG
evdPanel_Change(struct IClass *cl, Object *obj, Msg msg)
{
	struct paletteEntry* pal;
	struct evdPanelData* data = INST_DATA(cl, obj);

	DoMethod(data->LV_Palettes, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &pal);
	if (pal)
	{
		pal_list_change_entry(pal, (char*)xget(data->ST_PaletteName, MUIA_String_Contents));
		DoMethod(data->LV_Palettes, MUIM_List_Redraw, MUIV_List_Redraw_Active);
	}
	return 0;
}

/*
 *  SYNOPSIS
 *      evdPanel_New(class, object, message)
 *
 *  FUNCTION
 *      Inserts a new listview entry.
 */

static ULONG
evdPanel_New(struct IClass* cl, Object* obj, Msg msg)
{
	struct evdPanelData* data = INST_DATA(cl, obj);

	DoMethod(data->LV_Palettes, MUIM_List_InsertSingle, "(not named)", MUIV_List_Insert_Active);
	DoMethod(data->LV_Palettes, MUIM_List_Redraw, MUIV_List_Insert_Active);
	DoMethod(obj, MUIM_evdPanel_SetState);

	return 0;
}

/*
 *  SYNOPSIS
 *      evdPanel_Edit(class, object, message)
 *
 *  FUNCTION
 *      Edit is triggered by either clicking on edit button
 *      or doubleclicking a listview entry. It creates
 *      a new instance of paletteWindow class.
 *
 */

static ULONG evdPanel_Edit(struct IClass* cl, Object* obj, Msg msg)
{
	struct paletteEntry* pal;
	struct evdPanelData* data = INST_DATA(cl, obj);

	DoMethod(data->LV_Palettes, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &pal);
	if (pal)
	{
		set((Object*)xget(obj, MUIA_ApplicationObject), MUIA_Application_Sleep, TRUE);

		if (!pal->palWindow)
		{
			pal->palWindow = NewObject(CL_paletteWindow->mcc_Class, NULL,
				MUIA_Window_Width, MUIV_Window_Width_MinMax(0),
				MUIA_Window_Height, MUIV_Window_Height_MinMax(0),
				MUIA_paletteWindow_Palette, (ULONG)pal,
				MUIA_paletteWindow_Orig, (ULONG)obj,
				TAG_DONE);
			if (pal->palWindow)
			{
				 DoMethod((Object*)xget(obj, MUIA_ApplicationObject), OM_ADDMEMBER, pal->palWindow);
			}
		}

		if (pal->palWindow)
			set(pal->palWindow, MUIA_Window_Open, TRUE);
		else
			DisplayBeep(NULL);

		set((Object*)xget(obj, MUIA_ApplicationObject), MUIA_Application_Sleep, FALSE);
	}

	return 0;
}

/*
 *  SYNOPSIS
 *      evdPanel_Delete(class, object, message)
 *
 *  FUNCTION
 *      Deletes the active listview entry.
 */

static ULONG
evdPanel_Delete(struct IClass* cl, Object* obj, Msg msg)
{
	struct paletteEntry* pal = NULL;
	struct evdPanelData* data = INST_DATA(cl, obj);

	DoMethod(data->LV_Palettes, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &pal);
	if (pal)
	{
		if (!pal->palWindow)
		{
			DoMethod(data->LV_Palettes, MUIM_List_Remove, MUIV_List_Remove_Active);
			DoMethod(obj, MUIM_evdPanel_SetState);
		}
		else
			DisplayBeep(NULL);
	}

	return 0;
}

/*
 *  SYNOPSIS
 *      pal_list_change_entry(palette, new_string)
 *
 *  FUNCTION
 *      Replaces the old contents of a listview entry.
 */

static BOOL
pal_list_change_entry( struct paletteEntry* pal, char* str_new)
{
	if (pal->name)
		FreeVec(pal->name);
	pal->name = AllocVec(strlen(str_new)+1, MEMF_ANY);
	if (!pal->name)
		return FALSE;
	strcpy(pal->name, str_new);

	return TRUE;
}

/*
 *  SYNOPSIS
 *      pal_list_construct_hook(mem_pool, string)
 *
 *  FUNCTION
 *      A replacement insertion function for listviews. This one
 *      gets a string as parameter and outputs a paletteEntry.
 *      This means that instead of strings this listview actually
 *      consists of paletteEntries which is logically correct.
 */

static struct paletteEntry* REGARGS SAVEDS
pal_list_construct_hook(REG(a2, APTR pool), REG(a1, char* str))
{
	struct paletteEntry* pal;
	int i;

	pal = AllocPooled(pool, sizeof (*pal));
	if (pal)
	{
		pal->palWindow = NULL;
		pal->epsilon = 20;
		pal->name = AllocVec(strlen(str)+1, MEMF_ANY);
		pal->filename = AllocVec(strlen(DEFAULT_PALCACHE)+1, MEMF_ANY);

		if (pal->name && pal->filename)
		{
			strcpy(pal->name, str);
			strcpy(pal->filename, DEFAULT_PALCACHE);

			for (i = 0; i < 64; i++)
				pal->rgb[i] = 0;

			return pal;
		}

		if (pal->name)
			FreeVec(pal->name);
		if (pal->filename)
			FreeVec(pal->filename);

		FreePooled(pool, pal, sizeof (*pal));
	}
	return 0;
}

/*
 *  SYNOPSIS
 *      pal_list_destruct_hook(mem_pool, palette)
 *
 *  FUNCTION
 *      A destruct hook which deallocates everything allocated.
 */

static void  REGARGS SAVEDS 
pal_list_destruct_hook(REG(a2, APTR pool), REG(a1, struct paletteEntry* pal))
{
	FreeVec(pal->name);
	FreeVec(pal->filename);
	FreePooled(pool, pal, sizeof (*pal));
}

/*
 *  SYNOPSIS
 *      pal_list_display_hook(string_array, palette)
 *
 *  FUNCTION
 *      Returns a palette name for a given paletteEntry.
 *      See MUI_List.doc for more information.
 */

static LONG  REGARGS SAVEDS
pal_list_display_hook(REG(a2, char **str_array), REG(a1, struct paletteEntry* pal))
{
	str_array[0] = pal->name;

	return 0;
}

static ULONG 
evdPanel_Load(struct IClass* cl, Object* obj, struct MUIP_evdPanel_Prefs* msg)
{
	struct evdPanelData* data;
	struct palette_entry* src_pal;
	struct paletteEntry* dest_pal = NULL;
	ALIGNED struct FileInfoBlock fib;
	BPTR file;
	int i,j;
	struct TagItem* tags,* tag;

	data = INST_DATA(cl, obj);

	data->refreshrate = 0;
	data->numpals = 0;
	data->usedpal = 0;
	data->bblank = TRUE;
	data->own_refresh = FALSE;
	data->copyback_buffer = TRUE;
	data->imprecise_bitplanes = TRUE;

	DoMethod(obj, MUIM_evdPanel_CloseWindows);
	for ( i = xget(data->LV_Palettes, MUIA_List_Entries) - 1 ; i >= 0 ; i-- )
		DoMethod(data->LV_Palettes, MUIM_List_Remove, i);

	file = Open(msg->name, MODE_OLDFILE);
	if (file)
	{
		if (ExamineFH(file, &fib))
		{
			tags = AllocVec(fib.fib_Size, MEMF_ANY);
			if (tags)
			{
				i = Read(file, tags, fib.fib_Size);
				if (i == fib.fib_Size && tags->ti_Tag == EVD_Version && tags->ti_Data <=  PREFS_VERSION)
				{
					if (tag = FindTagItem(EVD_BBlank, tags)) data->bblank = tag->ti_Data;
					if (tag = FindTagItem(EVD_OwnRefr, tags)) data->own_refresh = tag->ti_Data;
					if (tag = FindTagItem(EVD_RRate, tags)) data->refreshrate = tag->ti_Data;
					if (tag = FindTagItem(EVD_UsedPal, tags)) data->usedpal = tag->ti_Data;
					if (tag = FindTagItem(EVD_NumPals, tags)) data->numpals = tag->ti_Data;
					if (tag = FindTagItem(EVD_FCached, tags)) data->copyback_buffer = tag->ti_Data;
					if (tag = FindTagItem(EVD_CImprec, tags)) data->imprecise_bitplanes = tag->ti_Data;
					if (tag = FindTagItem(EVD_Palette, tags))
					{
						src_pal = (struct palette_entry*) ((char*)tags + tag->ti_Data);
						for ( i = 0; i < data->numpals ; i++)
						{
							DoMethod(data->LV_Palettes, MUIM_List_InsertSingle, (char*)tags + src_pal[i].off_palname, MUIV_List_Insert_Bottom);
							set(data->LV_Palettes, MUIA_List_Active, MUIV_List_Active_Bottom);
							DoMethod(data->LV_Palettes, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &dest_pal);
							dest_pal->filename = AllocVec(strlen((char*)tags + src_pal[i].off_cached_palname)+1, MEMF_ANY);
							strcpy(dest_pal->filename, (char*)tags + src_pal[i].off_cached_palname);
							dest_pal->epsilon = src_pal[i].epsilon;
							for ( j = 0; j < 64 ; j++)
								dest_pal->rgb[j] = src_pal[i].rgb[j];
						}
					}

					set(data->LV_Palettes, MUIA_List_Active, data->usedpal);
				}
				else
					MUI_Request((APTR)xget(obj, MUIA_ApplicationObject),
								NULL, 0, NULL, "Okay",
								"This doesn't seem to be a TurboEVD\n"
								"preferences file of version %ld or lower.",
								PREFS_VERSION);
				FreeVec(tags);
			}
		}
		Close(file);
	}
	else
		MUI_Request((APTR)xget(obj, MUIA_ApplicationObject),
					NULL, 0, NULL, "Okay",
					"Cannot open the preferences file: %s.",
					msg->name);

	DoMethod(obj, MUIM_evdPanel_SetState);
	return 0;
}

static ULONG
evdPanel_Save(struct IClass* cl, Object* obj, struct MUIP_evdPanel_Prefs* msg)
{
	BPTR file;
	struct TagItem tag;
	struct evdPanelData* data;
	struct paletteEntry* src_pal;
	struct palette_entry dest_pal;
	char* strings;
	int i, j, k, off_string;

	data = INST_DATA(cl, obj);

	strings = AllocVec(8092, MEMF_ANY);               /* FIXME: a hardcoded limit */
	if (!strings)
		return 0;

	file = Open(msg->name, MODE_NEWFILE);
	if (file)
	{
		i = 0;
		DoMethod(obj, MUIM_evdPanel_GetState);
		tag.ti_Tag = EVD_Version; tag.ti_Data = PREFS_VERSION;
		Write(file, &tag, sizeof (tag)); i += sizeof (tag);
		tag.ti_Tag = EVD_BBlank; tag.ti_Data = data->bblank;
		Write(file, &tag, sizeof (tag)); i += sizeof (tag);
		tag.ti_Tag = EVD_OwnRefr; tag.ti_Data = data->own_refresh;
		Write(file, &tag, sizeof (tag)); i += sizeof (tag);
		tag.ti_Tag = EVD_RRate; tag.ti_Data = data->refreshrate;
		Write(file, &tag, sizeof (tag)); i += sizeof (tag);
		if (data->numpals)
		{
			tag.ti_Tag = EVD_UsedPal; tag.ti_Data = data->usedpal;
			Write(file, &tag, sizeof (tag)); i += sizeof (tag);
		}
		tag.ti_Tag = EVD_NumPals; tag.ti_Data = data->numpals;
		Write(file, &tag, sizeof (tag)); i += sizeof (tag);
		tag.ti_Tag = EVD_FCached; tag.ti_Data = data->copyback_buffer;
		Write(file, &tag, sizeof (tag)); i += sizeof (tag);
		tag.ti_Tag = EVD_CImprec; tag.ti_Data = data->imprecise_bitplanes;
		Write(file, &tag, sizeof (tag)); i += sizeof (tag);
		if (data->numpals)
		{
			tag.ti_Tag = EVD_Palette; tag.ti_Data = i + 2 * sizeof (tag);
			Write(file, &tag, sizeof (tag)); i += sizeof (tag);
		}
		tag.ti_Tag = TAG_END; tag.ti_Data = 0;
		Write(file, &tag, sizeof (tag)); i += sizeof (tag);

		off_string = 0;
		for ( j = 0 ; j < data->numpals ; j++)
		{
			DoMethod(data->LV_Palettes, MUIM_List_GetEntry, j, &src_pal);
			dest_pal.epsilon = src_pal->epsilon;
			for (k = 0; k < 64 ; k++)
				dest_pal.rgb[k] = src_pal->rgb[k];

			dest_pal.off_palname = i + off_string + sizeof (dest_pal) * data->numpals;
			strcpy(strings + off_string, src_pal->name);
			off_string += strlen(src_pal->name) + 1;
			dest_pal.off_cached_palname = i + off_string + sizeof (dest_pal) * data->numpals;
			strcpy(strings + off_string, src_pal->filename);
			off_string += strlen(src_pal->filename) + 1;

			Write(file, &dest_pal, sizeof (dest_pal) );
		}
		if (off_string)
			Write(file, strings, off_string);

		Close(file);
	}
	else
		MUI_Request((APTR)xget(obj, MUIA_ApplicationObject),
					NULL, 0, NULL, "Okay",
					"Cannot open the output file: %s.",
					msg->name);

	FreeVec(strings);

	return 0;
}

static ULONG
evdPanel_NEW(struct IClass* cl, Object* obj, struct opSet* msg)
{
	static const struct Hook evdPanel_ConstructHook = { { 0,0 }, (void*)pal_list_construct_hook, NULL, NULL };
	static const struct Hook evdPanel_DestructHook  = { { 0,0 }, (void*)pal_list_destruct_hook , NULL, NULL };
	static const struct Hook evdPanel_DisplayHook   = { { 0,0 }, (void*)pal_list_display_hook  , NULL, NULL };

	struct evdPanelData* data;
	Object* BT_New;
	Object* BT_Edit;
	Object* BT_Delete;
	Object* CM_BBlank;
	Object* CM_FCached;
	Object* CM_OwnRefr;
	Object* CM_CImpres;
	Object* SL_RRate;
	Object* LV_Palettes;
	Object* ST_PaletteName;

	obj = (Object*)DoSuperNew(cl, obj,
		Child, HGroup,
			Child, VGroup,
				Child, ColGroup(2), GroupFrameT("Miscellaneous"),
					Child, CM_BBlank = MakeCheck("Border blank"),
					Child, MakeLLabel1("Border blank"),
					Child, CM_FCached = MakeCheck("Change fast mem cache mode"),
					Child, MakeLLabel1("Change fast mem cache mode"),
					Child, CM_CImpres = MakeCheck("Optimize chip mem performance"),
					Child, MakeLLabel1("Optimize chip mem performance"),
				End,
				Child, VGroup, GroupFrameT("Refresh options"),
					Child, HGroup,
						Child, MakeLLabel1("Own refresh timing"),
						Child, CM_OwnRefr = MakeCheck("Own refresh timing"),
					End,
					Child, HGroup,
						Child, MakeLLabel1("Refresh rate"),
						Child, SL_RRate = MakeSlider(0,60,"Refresh rate"),
					End,
				End,
			End,
			Child, VGroup, GroupFrameT("HAM8 palette control"),
				MUIA_Group_VertSpacing, 0,
				Child, LV_Palettes = ListviewObject,
					MUIA_CycleChain, TRUE,
					MUIA_Listview_MultiSelect, MUIV_Listview_MultiSelect_None,
					MUIA_Listview_Input, TRUE,
					MUIA_Listview_List, ListObject,
						InputListFrame,
						MUIA_List_DragSortable, TRUE,
						MUIA_List_ConstructHook, &evdPanel_ConstructHook,
						MUIA_List_DestructHook, &evdPanel_DestructHook,
						MUIA_List_DisplayHook, &evdPanel_DisplayHook,
					End,
				End,
				Child, HGroup,
					Child, MakeLLabel1("Default:"),
					Child, ST_PaletteName = MakeString(40,"Default:"),
				End,
				Child, ColGroup(3), GroupSpacing(0), MUIA_Group_SameSize, TRUE,
					Child, BT_New = MakeButton("_New"),
					Child, BT_Edit = MakeButton("_Edit"),
					Child, BT_Delete = MakeButton("_Delete"),
				End,
			End,
		End,
	TAG_MORE,msg->ops_AttrList);

	if (!obj)
		return 0;

	data = INST_DATA(cl, obj);

	data->BT_Edit       = BT_Edit;
	data->BT_Delete     = BT_Delete;
	data->BT_New        = BT_New;
	data->CM_OwnRefr    = CM_OwnRefr;
	data->CM_BBlank     = CM_BBlank;
	data->CM_FCached    = CM_FCached;
	data->CM_OwnRefr    = CM_OwnRefr;
	data->CM_CImpres    = CM_CImpres;
	data->ST_PaletteName = ST_PaletteName;
	data->LV_Palettes   = LV_Palettes;
	data->SL_RRate      = SL_RRate;

	data->bblank = TRUE;
	data->own_refresh = FALSE;
	data->copyback_buffer = TRUE;
	data->imprecise_bitplanes = TRUE;
	data->refreshrate = 0;
	data->numpals = 0;
	data->usedpal = 0;

	DoMethod(data->CM_OwnRefr, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, data->SL_RRate, 3, MUIM_Set, MUIA_Disabled, MUIV_NotTriggerValue);
	DoMethod(data->BT_New, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, MUIM_evdPanel_New);
	DoMethod(data->BT_Edit, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, MUIM_evdPanel_Edit);
	DoMethod(data->BT_Delete, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, MUIM_evdPanel_Delete);
	DoMethod(data->ST_PaletteName, MUIM_Notify, MUIA_String_Acknowledge, MUIV_EveryTime, obj, 1, MUIM_evdPanel_Change);
	DoMethod(data->LV_Palettes, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime, obj, 1, MUIM_evdPanel_SetState);

	set(ST_PaletteName, MUIA_String_AttachedList, LV_Palettes);

	set(BT_New,     MUIA_ShortHelp,"Create a new base palette.");
	set(BT_Edit,    MUIA_ShortHelp,"Edit the selected base palette.");
	set(BT_Delete,  MUIA_ShortHelp,"Delete the selected base palette.");

	set(data->CM_OwnRefr, MUIA_ShortHelp, "Use own refresh timing\n"
										  "instead of the ShapeShifter one.\n"
										  "This enables silky smooth mouse\n"
										  "pointers.");
	set(data->CM_BBlank,  MUIA_ShortHelp, "Make the border of the MacOS screen\n"
										  "appear blanked instead of the background\n"
										  "color.");
	set(data->CM_FCached, MUIA_ShortHelp, "If not selected make the chunky framebuffer\n"
										  "cached as writethrough instead of copyback.\n"
										  "This may help in some situations.");
	set(data->CM_CImpres, MUIA_ShortHelp, "Make the planar buffers in chip mem cached\n"
										  "as imprecise/non-serialized instead of the\n"
										  "default precise/serialized.\n"
										  "This will definately help with M68060.");

	set(data->SL_RRate,   MUIA_ShortHelp, "The amount of frames skipped before\n"
										  "refreshing the display again.");

	return (ULONG)obj;
}

/*
 *  NAME
 *      evdPanel_Dispatcher -- the method dispatcher for evdPanel class.
 *
 */

ULONG REGARGS SAVEDS
evdPanel_Dispatcher(REG(a0, struct IClass* cl),REG(a2, Object* obj),REG(a1, Msg msg))
{
	switch (msg->MethodID)
	{
		case OM_NEW:                return evdPanel_NEW(cl, obj, (struct opSet*)msg);
		case MUIM_evdPanel_SetState: return evdPanel_SetState(cl, obj, msg);
		case MUIM_evdPanel_GetState: return evdPanel_GetState(cl, obj, msg);
		case MUIM_evdPanel_Load:    return evdPanel_Load(cl, obj, (struct MUIP_evdPanel_Prefs*)msg);
		case MUIM_evdPanel_Save:    return evdPanel_Save(cl, obj, (struct MUIP_evdPanel_Prefs*)msg);
		case MUIM_evdPanel_New:     return evdPanel_New(cl, obj, msg);
		case MUIM_evdPanel_Edit:    return evdPanel_Edit(cl, obj, msg);
		case MUIM_evdPanel_Delete:  return evdPanel_Delete(cl, obj, msg);
		case MUIM_evdPanel_Change:  return evdPanel_Change(cl, obj, msg);
		case MUIM_evdPanel_Finish:  return evdPanel_Finish(cl, obj, (struct MUIP_evdPanel_Finish*)msg);
		case MUIM_evdPanel_CloseWindows: return evdPanel_CloseWindows(cl, obj, msg);
	}

	return DoSuperMethodA(cl, obj, msg);
}
