/*
**	termStringHook.c
**
**	Custom string gadget editing hook routines
**
**	Copyright © 1990-1992 by Olaf `Olsen' Barthel & MXM
**		All Rights Reserved
*/

#include "termGlobal.h"

	/* Partial gadget support information. */

struct PartialGadgetSupportInfo
{
	STRPTR	Original,	/* Password string entry, original contents (for undo). */
		Buffer;		/* Password string entry, current contents. */
};

	/* CommandKey(struct Hook *Hook,struct SGWork *Work,ULONG *Msg):
	 *
	 *	This routine is called whenever input passes through
	 *	a `term' string gadget. It releases the currently
	 *	active string gadget as soon as the Right-Amiga-key is
	 *	pressed (user is about to select a menu item).
	 */

ULONG __saveds
CommandKey(struct Hook *Hook,struct SGWork *Work,ULONG *Msg)
{
	if(Msg[0] == SGH_KEY)
	{
			/* Simple: activate the next gadget if
			 * return is pressed in the current one.
			 */

		if(Work -> Actions & SGA_END)
		{
			if(!(Work -> GadgetInfo -> gi_Window -> Flags & WFLG_RMBTRAP))
				Work -> Actions |= SGA_NEXTACTIVE;
			else
				ActiveGadget = NULL;
		}

			/* This looks like a built-in command. */

		if(Work -> IEvent -> ie_Qualifier & IEQUALIFIER_RCOMMAND)
		{
				/* Amiga+C = Copy contents of string
				 *           gadget to the clipboard.
				 */

			if(Work -> Code == 'c')
			{
				Work -> Actions &= ~SGA_USE;
				Work -> Actions |= SGA_BEEP;

					/* Valid buffer contents? */

				if(Work -> PrevBuffer[0])
				{
					struct MsgPort *ReplyPort;

						/* Post a message... */

					if(ReplyPort = CreateMsgPort())
					{
						struct Message ClipMessage;

						ClipMessage . mn_Node . ln_Name	= Work -> PrevBuffer;
						ClipMessage . mn_ReplyPort	= ReplyPort;
						ClipMessage . mn_Length		= sizeof(struct Message);

						PutMsg(ClipPort,&ClipMessage);

						WaitPort(ReplyPort);

						GetMsg(ReplyPort);

						DeleteMsgPort(ReplyPort);

						Work -> Actions &= ~SGA_BEEP;
					}
				}

				return(~0);
			}

				/* Amiga+V = Insert current clipboard
				 *           contents at cursor position.
				 */

			if(Work -> Code == 'v')
			{
				Work -> Actions &= ~SGA_USE;
				Work -> Actions |= SGA_BEEP;

					/* Don't paste to integer gadgets
					 * (it could confuse Intuition if
					 *  the buffer contained non-numeric
					 *  symbols...).
					 */

				if(!(Work -> Gadget -> Activation & GACT_LONGINT))
				{
					struct MsgPort *ReplyPort;

						/* Post a message... */

					if(ReplyPort = CreateMsgPort())
					{
						STATIC UBYTE	Buffer[2048];
						struct Message	ClipMessage;

						Buffer[0] = 0;

						ClipMessage . mn_Node . ln_Name	= Buffer;
						ClipMessage . mn_ReplyPort	= ReplyPort;
						ClipMessage . mn_Length		= sizeof(struct Message);

						PutMsg(ClipPort,&ClipMessage);

						WaitPort(ReplyPort);

						GetMsg(ReplyPort);

						DeleteMsgPort(ReplyPort);

							/* Anything in the buffer? */

						if(Buffer[0])
						{
							WORD Len = strlen(Buffer);

								/* Insert as many characters as we can. */

							while(Len > 0 && Work -> NumChars + Len > Work -> StringInfo -> MaxChars)
								Len--;

								/* Any characters left? */

							if(Len > 0)
							{
								STATIC UBYTE OtherBuffer[2048];

									/* Provide null-termination. */

								Buffer[Len] = 0;

									/* Set up undo buffer correctly. */

								if(Work -> StringInfo -> UndoBuffer)
									strcpy(Work -> StringInfo -> UndoBuffer,Work -> PrevBuffer);

								Work -> StringInfo -> UndoPos = --Work -> BufferPos;

									/* Save the characters before the cursor. */

								if(Work -> BufferPos)
									CopyMem(Work -> PrevBuffer,OtherBuffer,Work -> BufferPos);

									/* Provide null-termination. */

								OtherBuffer[Work -> BufferPos] = 0;

									/* Append the clipboard data. */

								strcat(OtherBuffer,Buffer);

									/* Append the characters following the cursor. */

								strcat(OtherBuffer,&Work -> PrevBuffer[Work -> BufferPos]);

									/* = new work buffer. */

								strcpy(Work -> WorkBuffer,OtherBuffer);

									/* Fiddle with some cursor data. */

								Work -> BufferPos += Len;
								Work -> NumChars	+= Len;

									/* And that's it... */

								Work -> Actions	|= SGA_USE;
								Work -> EditOp	 = EO_BIGCHANGE;

								Work -> Actions &= ~SGA_BEEP;
							}
						}
						else
							Work -> Actions &= ~SGA_BEEP;
					}
				}

				return(~0);
			}
		}

			/* Release the gadget in case a menu item is to be selected. */

		if((Work -> IEvent -> ie_Qualifier & AMIGARIGHT) && Work -> IEvent -> ie_Code < 96)
		{
			if(!(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)) && (Work -> IEvent -> ie_Code == KEYCODE_X || Work -> IEvent -> ie_Code == KEYCODE_Q))
				return(~0);
			else
			{
				Work -> Actions |= (SGA_END|SGA_REUSE);
				Work -> Actions &= ~(SGA_USE|SGA_BEEP);

				CommandWindow = Work -> GadgetInfo -> gi_Window;
				CommandGadget = Work -> Gadget;
			}
		}

			/* The user pressed the cursor-right key to
			 * move the cursor to the next word in the buffer.
			 */

		if(Work -> IEvent -> ie_Code == CURSORRIGHT && (Work -> IEvent -> ie_Qualifier & IEQUALIFIER_CONTROL))
		{
			if(Work -> BufferPos != Work -> NumChars)
			{
				WORD i,Position = -1;

				for(i = Work -> BufferPos ; i < Work -> NumChars ; i++)
				{
					if(Work -> WorkBuffer[i] == ' ')
					{
						for( ; i < Work -> NumChars ; i++)
						{
							if(Work -> WorkBuffer[i] != ' ')
							{
								Position = i;
								break;
							}
						}

						break;
					}
				}

				if(Position != -1)
					Work -> BufferPos = Position;
				else
					Work -> BufferPos = Work -> NumChars;

				Work -> EditOp = EO_MOVECURSOR;
			}
		}

			/* The user pressed the cursor-right key to
			 * move the cursor to the previous word in the buffer.
			 */

		if(Work -> IEvent -> ie_Code == CURSORLEFT && (Work -> IEvent -> ie_Qualifier & IEQUALIFIER_CONTROL))
		{
			if(Work -> BufferPos)
			{
				WORD i,Position = -1;

				for(i = Work -> BufferPos ; i >= 0 ; i--)
				{
					if(Work -> WorkBuffer[i] != ' ')
					{
						Position = i;
						break;
					}
				}

				if(Position == -1)
					Position = 0;

				if(Position)
				{
					i = Position;

					Position = -1;

					for( ; i >= 0 ; i--)
					{
						if(Work -> WorkBuffer[i] == ' ')
						{
							Position = i + 1;
							break;
						}
					}
				}

				if(Position != -1)
					Work -> BufferPos = Position;
				else
					Work -> BufferPos = 0;

				Work -> EditOp = EO_MOVECURSOR;
			}
		}
	}
	else
		return(~0);
}

	/* PasswordKey(struct Hook *Hook,struct SGWork *Work,ULONG *Msg):
	 *
	 *	Editing code for a password-entry string gadget. Credits for
	 *	the original implementation go to Hans-Joachim Widmaier.
	 */

ULONG __saveds
PasswordKey(struct Hook *Hook,struct SGWork *Work,ULONG *Msg)
{
	struct PartialGadgetSupportInfo	*Info = (struct PartialGadgetSupportInfo *)Work -> Gadget -> UserData;
	LONG				 Len;

	switch(Msg[0])
	{
			/* Some key was pressed. */

		case SGH_KEY:	switch(Work -> EditOp)
				{
						/* Entered another character. */

					case EO_INSERTCHAR:	Info -> Buffer[Work -> BufferPos - 1]		= Work -> Code;
								Info -> Buffer[Work -> NumChars]		= 0;

								Work -> Code = '*';
								Work -> WorkBuffer[Work -> BufferPos - 1]	= '*';

								break;

						/* Undo changes. */

					case EO_RESET:		Len = strlen(Info -> Original);

								strcpy(Info -> Buffer,Info -> Original);

								memset(Work -> WorkBuffer,'*',Len);

								Work -> WorkBuffer[Len] = 0;

								Work -> NumChars	= Len;
								Work -> BufferPos	= Len;
								Work -> EditOp	 	= EO_BIGCHANGE;

								break;

						/* Clear the gadget. */

					case EO_CLEAR:		Work -> WorkBuffer[0]	= 0;
								Work -> NumChars	= 0;
								Work -> BufferPos	= 0;
								Work -> EditOp	 	= EO_BIGCHANGE;

								Info -> Buffer[0]	= 0;

								break;

						/* Deleted the last character. */

					case EO_DELBACKWARD:	Info -> Buffer[Work -> NumChars] = 0;
								break;

						/* Default. */

					case EO_NOOP:		break;

						/* Terminate input. */

					case EO_ENTER:		strcpy(Info -> Original,Info -> Buffer);
								break;

						/* Don't move the cursor or try to
						 * delete from the middle of the string.
						 */

					case EO_MOVECURSOR:
					case EO_DELFORWARD:	Work -> Actions &= ~SGA_USE;
								break;

						/* Reject the rest. */

					default:		Work -> Actions &= ~SGA_USE;
								Work -> Actions	|= SGA_BEEP;
								break;
				}

				return(~0);

			/* Clicking inside the box sets up the defaults. */

		case SGH_CLICK:	Work -> BufferPos	= Work -> NumChars;
				Work -> EditOp	 	= EO_BIGCHANGE;

				return(~0);

			/* Reject the rest. */

		default:	return(0);
	}
}
