/*
**	termStringHook.c
**
**	Custom string gadget editing hook routines
**
**	Copyright © 1990-1993 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 == SGH_KEY)
	{
		if(Work -> EditOp == EO_ENTER)
		{
			if(!(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)))
				Work -> Actions |= SGA_NEXTACTIVE;
			else
				Work -> Code = '\t';
		}

		if(Work -> EditOp == EO_INSERTCHAR || Work -> EditOp == EO_REPLACECHAR)
		{
				/* 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(1);
				}

					/* 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(1);
				}
			}

				/* 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(1);
				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;
			}
		}

		return(1);
	}
	else
	{
		if(*Msg == SGH_CLICK)
			return(1);
		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)
	{
			/* 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(1);

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

		case SGH_CLICK:

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

			return(1);

			/* Reject the rest. */

		default:

			return(0);
	}
}
