/*
**	HotkeyPanel.c
**
**	Editing panel for hotkey configuration
**
**	Copyright © 1990-1996 by Olaf `Olsen' Barthel
**		All Rights Reserved
*/

#ifndef _GLOBAL_H
#include "Global.h"
#endif

enum	{	GAD_TERMTOFRONT=1,GAD_BUFFERTOFRONT,GAD_SKIPDIAL,GAD_ABORTAREXX,
		GAD_PRIORITY,GAD_HOTKEYS,GAD_USE,GAD_LOAD,GAD_SAVE,GAD_CANCEL,
		GAD_DISCARD
	};

STATIC struct Library *KeymapBase;

	// All the rawkey codes we know about

#define RAWKEY_CURSOR_UP	76
#define RAWKEY_CURSOR_DOWN	77
#define RAWKEY_CURSOR_RIGHT	78
#define RAWKEY_CURSOR_LEFT	79

#define RAWKEY_F1		80
#define RAWKEY_F2		81
#define RAWKEY_F3		82
#define RAWKEY_F4		83
#define RAWKEY_F5		84
#define RAWKEY_F6		85
#define RAWKEY_F7		86
#define RAWKEY_F8		87
#define RAWKEY_F9		88
#define RAWKEY_F10		89

#define RAWKEY_HELP		95

STATIC BOOL
GoodCode(STRPTR Code)
{
	IX Expression;

	return((BOOL)(ParseIX(Code,&Expression) == 0));
}

	/* EditRoutine():
	 *
	 *	A special string gadget editing routine for key
	 *	combination input.
	 */

STATIC ULONG __saveds __asm
EditRoutine(REG(a0) struct Hook *Hook,REG(a2) struct SGWork *Work,REG(a1) ULONG *Msg)
{
	struct InputEvent	Event;
	ULONG			Qualifier;
	UWORD			Code;
	UBYTE			Key[10];
	LONG			KeyLen;
	STRPTR			KeyName;

		// If the gadget just got activated or the caps lock key
		// is active, don't change anything

	if(*Msg == SGH_CLICK || (*Msg == SGH_KEY && (Work -> IEvent -> ie_Qualifier & IEQUALIFIER_CAPSLOCK)))
		return(TRUE);
	else
	{
			// Complain if this is not what we expect to be fun

		if(*Msg != SGH_KEY)
			return(FALSE);
	}

		// Ditch the qualifier keys

	if(Work -> IEvent -> ie_Code >= 96 && Work -> IEvent -> ie_Code <= 103)
	{
		Work -> Actions	&= ~(SGA_USE | SGA_BEEP);

		return(TRUE);
	}

		// Strip all the qualifiers we don't want

	Qualifier = Work -> IEvent -> ie_Qualifier & ~(IEQUALIFIER_REPEAT | IEQUALIFIER_INTERRUPT | IEQUALIFIER_MULTIBROADCAST | IEQUALIFIER_RELATIVEMOUSE);

		// Check for raw keys

	switch(Work -> IEvent -> ie_Code)
	{
		case RAWKEY_CURSOR_UP:
		case RAWKEY_CURSOR_DOWN:
		case RAWKEY_CURSOR_RIGHT:
		case RAWKEY_CURSOR_LEFT:

				// A cursor key was pressed, check if there
				// is probably some special feature involved

			if(!(Qualifier & ~(IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)))
				return(TRUE);

			// FALLS THROUGH TO:

		case RAWKEY_F1:
		case RAWKEY_F2:
		case RAWKEY_F3:
		case RAWKEY_F4:
		case RAWKEY_F5:
		case RAWKEY_F6:
		case RAWKEY_F7:
		case RAWKEY_F8:
		case RAWKEY_F9:
		case RAWKEY_F10:

		case RAWKEY_HELP:

				// Ok, so this is a raw key event

			Code	= Work -> IEvent -> ie_Code;
			KeyLen	= 0;

			break;

		default:

				// Make a copy of the inputevent and
				// clear the qualifier bits

			CopyMem(Work -> IEvent,&Event,sizeof(struct InputEvent));

			Event . ie_Qualifier = NULL;

			Code = 0;

				// Translate the event

			if((KeyLen = MapRawKey(&Event,Key,10,NULL)) < 0)
				KeyLen = 10;

			break;
	}

		// Is the user holding down a single Amiga key?

	if(KeyLen && (Qualifier & IEQUALIFIER_RCOMMAND) && !(Qualifier & ~IEQUALIFIER_RCOMMAND))
	{
		LONG Char = ToUpper(Key[0]);

			// Undo and clear are supported

		if(Char == 'Q' || Char == 'X')
			return(TRUE);
	}

		// Can we safely continue?

	if((!Code && !KeyLen) || KeyLen > 1 || (!Code && KeyLen && !Key[0]))
	{
		Work -> Actions	= (Work -> Actions & ~SGA_USE) | SGA_BEEP;

		return(TRUE);
	}

		// Take care of special characters

	if(KeyLen)
	{
		STATIC struct { UBYTE Code; STRPTR Name; } KeyTable[] =
		{
			'\r',	"Return",
			'\b',	"Backspace",
			'\033',	"Escape",
			' ',	"Spacebar",
			',',	"Comma",
			'\177',	"Delete",
			'\t',	"Tab",

			0
		};

		BOOL GotIt = FALSE;
		LONG i;

			// Carriage return was pressed

		if(Key[0] == '\r')
		{
				// This probably ends input

			if(!Qualifier)
			{
				Work -> Actions	= (Work -> Actions & ~SGA_BEEP) | SGA_USE | SGA_END;

				return(TRUE);
			}
			else
			{
					// Is this the enter key?

				if(Qualifier & IEQUALIFIER_NUMERICPAD)
				{
					KeyName = "Enter";

					Qualifier &= ~IEQUALIFIER_NUMERICPAD;

					GotIt = TRUE;
				}
			}
		}

			// If this is just the tab key, pass it through cleanly

		if(Key[0] == '\t' && !(Qualifier & ~(IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)))
			return(TRUE);

			// Now check for special characters

		Key[0] = ToUpper(Key[0]);

		if(!GotIt)
		{
			for(i = 0 ; KeyTable[i] . Code ; i++)
			{
				if(KeyTable[i] . Code == Key[0])
				{
					KeyName = KeyTable[i] . Name;

					GotIt = TRUE;

					break;
				}
			}
		}

			// If no special character is involved,
			// use the vanilla character code

		if(!GotIt)
		{
			if((Key[0] > ' ' && Key[0] < 127) || Key[0] >= 160)
			{
				Key[1] = 0;

				KeyName = Key;
			}
			else
			{
				Work -> Actions	= (Work -> Actions & ~SGA_USE) | SGA_BEEP;

				return(TRUE);
			}
		}
	}
	else
	{
			// Special raw key code table

		STATIC struct { UWORD Code; STRPTR Name; } RawTable[] =
		{
			RAWKEY_CURSOR_UP,	"Cursor_Up",
			RAWKEY_CURSOR_DOWN,	"Cursor_Down",
			RAWKEY_CURSOR_RIGHT,	"Cursor_Right",
			RAWKEY_CURSOR_LEFT,	"Cursor_Left",

			RAWKEY_F1,		"F1",
			RAWKEY_F2,		"F2",
			RAWKEY_F3,		"F3",
			RAWKEY_F4,		"F4",
			RAWKEY_F5,		"F5",
			RAWKEY_F6,		"F6",
			RAWKEY_F7,		"F7",
			RAWKEY_F8,		"F8",
			RAWKEY_F9,		"F9",
			RAWKEY_F10,		"F10",

			RAWKEY_HELP,		"Help",

			0
		};

		LONG i;

			// One eventually must match

		for(i = 0 ; RawTable[i] . Code ; i++)
		{
			if(Code == RawTable[i] . Code)
			{
				KeyName = RawTable[i] . Name;

				break;
			}
		}
	}

		// Take care of the qualifiers. Note that we do not distinguish
		// between the left and right shift/alt keys

	if(Qualifier)
	{
		STATIC struct { ULONG Qualifier; STRPTR Name; } QualifierTable[] =
		{
			IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT,	"Shift ",
			IEQUALIFIER_LALT | IEQUALIFIER_RALT,		"Alt ",
			IEQUALIFIER_LCOMMAND,				"LAmiga ",
			IEQUALIFIER_RCOMMAND,				"RAmiga ",
			IEQUALIFIER_LEFTBUTTON,				"Left_Button ",
			IEQUALIFIER_MIDBUTTON,				"Middle_Button ",
			IEQUALIFIER_RBUTTON,				"Right_Button ",
			IEQUALIFIER_NUMERICPAD,				"Numeric_Pad ",

			0
		};

		LONG i;

			// Ok, now start building the string

		Work -> WorkBuffer[0] = 0;

		for(i = 0 ; QualifierTable[i] . Qualifier ; i++)
		{
			if(Qualifier & QualifierTable[i] . Qualifier)
				strcat(Work -> WorkBuffer,QualifierTable[i] . Name);
		}

			// Add the key itself

		strcat(Work -> WorkBuffer,KeyName);

			// Update the work data

		Work -> NumChars	= strlen(Work -> WorkBuffer);
		Work -> BufferPos	= Work -> NumChars;

			// Finished...

		Work -> Actions	= (Work -> Actions & ~(SGA_BEEP | SGA_PREVACTIVE | SGA_NEXTACTIVE | SGA_END)) | SGA_REDISPLAY | SGA_USE;
	}
	else
		Work -> Actions	&= ~(SGA_USE | SGA_BEEP);

	return(TRUE);
}

BOOL
HotkeyPanelConfig(struct Configuration *LocalConfig,struct Hotkeys *Hotkeys,STRPTR LastKeys,BOOLEAN *ChangePtr)
{
	STATIC struct Hook EditHook = { {NULL}, (HOOKFUNC)EditRoutine };

	struct LayoutHandle	*Handle;
	struct Hotkeys		 PrivateHotkeys;
	BOOL			 Changed = FALSE;

	KeymapBase = OpenLibrary("keymap.library",0);

	CopyMem(Hotkeys,&PrivateHotkeys,sizeof(struct Hotkeys));

	if(Handle = LT_CreateHandleTags(Window -> WScreen,
		LH_LocaleHook,	&LocaleHook,
		LH_ExitFlush,	FALSE,
	TAG_DONE))
	{
		struct Window *PanelWindow;

		LT_New(Handle,
			LA_Type,	VERTICAL_KIND,
		TAG_DONE);
		{
			LT_New(Handle,
				LA_Type,	VERTICAL_KIND,
				LA_LabelID,	MSG_V36_0083,
			TAG_DONE);
			{
				LT_New(Handle,
					LA_Type,	STRING_KIND,
					LA_LabelID,	MSG_HOTKEYPANEL_TERM_SCREEN_TO_FRONT_GAD,
					LA_STRPTR,	PrivateHotkeys . termScreenToFront,
					LA_Chars,	30,
					GTST_MaxChars,	255,
					LA_ID,		GAD_TERMTOFRONT,

					KeymapBase ? GTST_EditHook : TAG_IGNORE,&EditHook,
				TAG_DONE);

				LT_New(Handle,
					LA_Type,	STRING_KIND,
					LA_LabelID,	MSG_HOTKEYPANEL_BUFFER_SCREEN_TO_FRONT_GAD,
					LA_STRPTR,	PrivateHotkeys . BufferScreenToFront,
					GTST_MaxChars,	255,
					LA_ID,		GAD_BUFFERTOFRONT,

					KeymapBase ? GTST_EditHook : TAG_IGNORE,&EditHook,
				TAG_DONE);

				LT_New(Handle,
					LA_Type,	STRING_KIND,
					LA_LabelID,	MSG_HOTKEYPANEL_SKIP_DIAL_ENTRY_GAD,
					LA_STRPTR,	PrivateHotkeys . SkipDialEntry,
					GTST_MaxChars,	255,
					LA_ID,		GAD_SKIPDIAL,

					KeymapBase ? GTST_EditHook : TAG_IGNORE,&EditHook,
				TAG_DONE);

				LT_New(Handle,
					LA_Type,	STRING_KIND,
					LA_LabelID,	MSG_HOTKEYPANEL_ABORT_AREXX_GAD,
					LA_STRPTR,	PrivateHotkeys . AbortARexx,
					GTST_MaxChars,	255,
					LA_ID,		GAD_ABORTAREXX,

					KeymapBase ? GTST_EditHook : TAG_IGNORE,&EditHook,
				TAG_DONE);

				LT_EndGroup(Handle);
			}

			LT_New(Handle,
				LA_Type,		VERTICAL_KIND,
				LA_LabelID,		MSG_V36_0084,
			TAG_DONE);
			{
				LT_New(Handle,
					LA_Type,		SliderType,
					LA_LabelID,		MSG_HOTKEYPANEL_COMMODITY_PRIORITY_GAD,
					LA_BYTE,		&PrivateHotkeys . CommodityPriority,
					GTSL_Min,		-128,
					GTSL_Max,		127,
					GTSL_LevelFormat,	"%4ld",
					LA_Chars,		16,
					LA_ID,			GAD_PRIORITY,
				TAG_DONE);

				LT_New(Handle,
					LA_Type,	CHECKBOX_KIND,
					LA_LabelID,	MSG_HOTKEYPANEL_HOTKEYS_ENABLED_GAD,
					LA_BYTE,	&PrivateHotkeys . HotkeysEnabled,
					LA_ID,		GAD_HOTKEYS,
				TAG_DONE);

				LT_EndGroup(Handle);
			}

			LT_New(Handle,
				LA_Type,VERTICAL_KIND,
			TAG_DONE);
			{
				LT_New(Handle,
					LA_Type,	XBAR_KIND,
					LAXB_FullSize,	TRUE,
				TAG_DONE);

				LT_EndGroup(Handle);
			}

			LT_New(Handle,LA_Type,HORIZONTAL_KIND,
				LAGR_SameSize,	TRUE,
				LAGR_Spread,	TRUE,
			TAG_DONE);
			{
				LT_New(Handle,
					LA_Type,	BUTTON_KIND,
					LA_LabelID,	MSG_GLOBAL_USE_GAD,
					LA_ID,		GAD_USE,
					LABT_ReturnKey,	TRUE,
					LABT_ExtraFat,	TRUE,
				TAG_DONE);

				LT_New(Handle,
					LA_Type,	BUTTON_KIND,
					LA_LabelID,	MSG_GLOBAL_LOAD_GAD,
					LA_ID,		GAD_LOAD,
				TAG_DONE);

				LT_New(Handle,
					LA_Type,	BUTTON_KIND,
					LA_LabelID,	MSG_GLOBAL_SAVE_GAD,
					LA_ID,		GAD_SAVE,
				TAG_DONE);

				LT_New(Handle,
					LA_Type,	BUTTON_KIND,
					LA_LabelID,	MSG_DISCARD_GAD,
					LA_ID,		GAD_DISCARD,
				TAG_DONE);

				LT_New(Handle,
					LA_Type,	BUTTON_KIND,
					LA_LabelID,	MSG_GLOBAL_CANCEL_GAD,
					LA_ID,		GAD_CANCEL,
					LABT_EscKey,	TRUE,
				TAG_DONE);

				LT_EndGroup(Handle);
			}

			LT_EndGroup(Handle);
		}

		if(PanelWindow = LT_Build(Handle,
			LAWN_TitleID,		MSG_HOTKEYPANEL_HOTKEY_PREFERENCES_TXT,
			LAWN_IDCMP,		IDCMP_CLOSEWINDOW,
			LAWN_HelpHook,		&GuideHook,
			LAWN_Parent,		Window,
			WA_DepthGadget,		TRUE,
			WA_CloseGadget,		TRUE,
			WA_DragBar,		TRUE,
			WA_RMBTrap,		TRUE,
			WA_Activate,		TRUE,
			WA_SimpleRefresh,	TRUE,
		TAG_DONE))
		{
			struct IntuiMessage	*Message;
			BOOL			 Done = FALSE;
			ULONG			 MsgClass;
			struct Gadget		*MsgGadget;

			struct FileRequester	*FileRequest;
			UBYTE			 DummyBuffer[MAX_FILENAME_LENGTH],
						*DummyChar;

			STRPTR			 String;

			GuideContext(CONTEXT_HOTKEYS);

			PushWindow(PanelWindow);

			do
			{
				if(Wait(PORTMASK(PanelWindow -> UserPort) | SIG_BREAK) & SIG_BREAK)
				{
					Changed = FALSE;

					break;
				}

				while(Message = (struct IntuiMessage *)LT_GetIMsg(Handle))
				{
					MsgClass	= Message -> Class;
					MsgGadget	= (struct Gadget *)Message -> IAddress;

					LT_ReplyIMsg(Message);

					if(MsgClass == IDCMP_CLOSEWINDOW)
					{
						Changed = FALSE;
						Done = TRUE;
					}

					if(MsgClass == IDCMP_GADGETUP)
					{
						switch(MsgGadget -> GadgetID)
						{
							case GAD_TERMTOFRONT:
							case GAD_BUFFERTOFRONT:
							case GAD_SKIPDIAL:
							case GAD_ABORTAREXX:

								String = LT_GetString(Handle,MsgGadget -> GadgetID);

								if(!GoodCode(String))
								{
									DisplayBeep(PanelWindow -> WScreen);

									LT_Activate(Handle,MsgGadget -> GadgetID);
								}

								break;

							case GAD_USE:

								LT_UpdateStrings(Handle);

								CopyMem(&PrivateHotkeys,Hotkeys,sizeof(struct Hotkeys));

								Changed = TRUE;

								if(ChangePtr)
									*ChangePtr = TRUE;

								Done = TRUE;
								break;

							case GAD_DISCARD:

								if(ChangePtr)
									*ChangePtr = FALSE;

								LastKeys[0] = 0;
								Changed = Done = TRUE;

								if(LocalConfig)
									strcpy(LocalConfig->HotkeyFileName,LastKeys);

								break;

							case GAD_CANCEL:

								Changed = FALSE;
								Done = TRUE;
								break;

							case GAD_LOAD:

								SplitFileName(LastKeys,&DummyChar,DummyBuffer);

								LT_LockWindow(PanelWindow);

								if(FileRequest = GetFile(PanelWindow,LocaleString(MSG_HOTKEYPANEL_LOAD_HOTKEYS_TXT),DummyBuffer,FilePart(LastKeys),DummyBuffer,"#?.prefs",FALSE,FALSE,FALSE,LocaleString(MSG_GLOBAL_LOAD_TXT),TRUE))
								{
									if(!LoadHotkeys(DummyBuffer,&PrivateHotkeys))
										ShowError(PanelWindow,ERR_LOAD_ERROR,IoErr(),DummyBuffer);
									else
									{
										strcpy(LastKeys,DummyBuffer);

										if(LocalConfig)
											strcpy(LocalConfig->HotkeyFileName,LastKeys);

										LT_SetAttributes(Handle,GAD_TERMTOFRONT,
											GTST_String,PrivateHotkeys . termScreenToFront,
										TAG_DONE);

										LT_SetAttributes(Handle,GAD_BUFFERTOFRONT,
											GTST_String,PrivateHotkeys . BufferScreenToFront,
										TAG_DONE);

										LT_SetAttributes(Handle,GAD_SKIPDIAL,
											GTST_String,PrivateHotkeys . SkipDialEntry,
										TAG_DONE);

										LT_SetAttributes(Handle,GAD_ABORTAREXX,
											GTST_String,PrivateHotkeys . AbortARexx,
										TAG_DONE);

										LT_SetAttributes(Handle,GAD_PRIORITY,
											GTSL_Level,PrivateHotkeys . CommodityPriority,
										TAG_DONE);

										LT_SetAttributes(Handle,GAD_HOTKEYS,
											GTCB_Checked,PrivateHotkeys . HotkeysEnabled,
										TAG_DONE);

										Changed = TRUE;

										if(ChangePtr)
											*ChangePtr = FALSE;
									}

									FreeAslRequest(FileRequest);
								}

								LT_UnlockWindow(PanelWindow);

								break;

							case GAD_SAVE:

								LT_UpdateStrings(Handle);

								SplitFileName(LastKeys,&DummyChar,DummyBuffer);

								LT_LockWindow(PanelWindow);

								if(FileRequest = GetFile(PanelWindow,LocaleString(MSG_HOTKEYPANEL_SAVE_HOTKEYS_TXT),DummyBuffer,FilePart(LastKeys),DummyBuffer,"#?.prefs",TRUE,FALSE,FALSE,LocaleString(MSG_GLOBAL_SAVE_TXT),TRUE))
								{
									if(!WriteIFFData(DummyBuffer,&PrivateHotkeys,sizeof(struct Hotkeys),ID_HOTK))
										ShowError(PanelWindow,ERR_SAVE_ERROR,IoErr(),DummyBuffer);
									else
									{
										strcpy(LastKeys,DummyBuffer);

										if(LocalConfig)
											strcpy(LocalConfig->HotkeyFileName,LastKeys);

										if(ChangePtr)
											*ChangePtr = FALSE;
									}

									FreeAslRequest(FileRequest);
								}

								LT_UnlockWindow(PanelWindow);

								break;
						}
					}
				}
			}
			while(!Done);

			PopWindow();
		}

		LT_DeleteHandle(Handle);
	}

	CloseLibrary(KeymapBase);

	return(Changed);
}
