		/*************************************
		 *                                   *
		 *             Editor v1.0           *
		 *   by Torsten Jürgeleit in 07/91   *
		 *                                   *
		 *          Subroutines part         *
		 *                                   *
		 *************************************/

	/* Includes */

#include "includes.h"
#include "defines.h"
#include "imports.h"
#include "protos.h"

	/* Draw box in given window */

   VOID
draw_box(struct Window  *win, struct Box  *box)
{
   struct RastPort  *rp = win->RPort;

   SetDrMd(rp, (LONG)COMPLEMENT);
   Move(rp, (LONG)box->bo_X1, (LONG)box->bo_Y1);
   Draw(rp, (LONG)box->bo_X2, (LONG)box->bo_Y1);
   Draw(rp, (LONG)box->bo_X2, (LONG)box->bo_Y2);
   Draw(rp, (LONG)box->bo_X1, (LONG)box->bo_Y2);
   Draw(rp, (LONG)box->bo_X1, (LONG)box->bo_Y1);
}
	/* Draw box in given window with border of 1 pixel */

   VOID
draw_box_with_border(struct Window  *win, struct Box  *box)
{
   struct RastPort  *rp = win->RPort;

   SetDrMd(rp, (LONG)COMPLEMENT);
   Move(rp, (LONG)(box->bo_X1 - 1), (LONG)(box->bo_Y1 - 1));
   Draw(rp, (LONG)(box->bo_X2 + 1), (LONG)(box->bo_Y1 - 1));
   Draw(rp, (LONG)(box->bo_X2 + 1), (LONG)(box->bo_Y2 + 1));
   Draw(rp, (LONG)(box->bo_X1 - 1), (LONG)(box->bo_Y2 + 1));
   Draw(rp, (LONG)(box->bo_X1 - 1), (LONG)(box->bo_Y1 - 1));
}
	/* Draw box in given window with offset */

   VOID
draw_box_with_offset(struct Window  *win, struct Box  *box, SHORT xoffset,
							      SHORT yoffset)
{
   struct RastPort  *rp = win->RPort;

   SetDrMd(rp, (LONG)COMPLEMENT);
   Move(rp, (LONG)(box->bo_X1 + xoffset), (LONG)(box->bo_Y1 + yoffset));
   Draw(rp, (LONG)(box->bo_X2 + xoffset), (LONG)(box->bo_Y1 + yoffset));
   Draw(rp, (LONG)(box->bo_X2 + xoffset), (LONG)(box->bo_Y2 + yoffset));
   Draw(rp, (LONG)(box->bo_X1 + xoffset), (LONG)(box->bo_Y2 + yoffset));
   Draw(rp, (LONG)(box->bo_X1 + xoffset), (LONG)(box->bo_Y1 + yoffset));
}
	/* Get head of EXEC list */

   VOID *
get_head(struct List  *list)
{
   struct Node  *node = list->lh_Head;

   /* empty list ? */
   if (!node->ln_Succ) {
      node = NULL;
   }
   return((VOID *)node);
}
	/* Get tail of EXEC list */

   VOID *
get_tail(struct List  *list)
{
   struct Node  *node = list->lh_TailPred;

   /* empty list ? */
   if (!node->ln_Pred) {
      node = NULL;
   }
   return((VOID *)node);
}
	/* Get next node of EXEC list entry */

   VOID *
get_succ(struct Node  *node)
{
   node = node->ln_Succ;
   /* end of list ? */
   if (!node->ln_Succ) {
      node = NULL;
   }
   return((VOID *)node);
}
	/* Get previous node of EXEC list entry */

   VOID *
get_pred(struct Node  *node)
{
   node = node->ln_Pred;
   /* start of list ? */
   if (!node->ln_Pred) {
      node = NULL;
   }
   return((VOID *)node);
}
	/* Get node from list by given number */

   VOID *
get_node(struct List  *list, USHORT num)
{
   struct Node  *node;

   if (node = get_head(list)) {
      while (num-- && (node = get_succ(node)));
   }
   return((VOID *)node);
}
	/* Duplicate text string */

   SHORT
duplicate_string(BYTE **ptr, BYTE *text)
{
   LONG len;
   SHORT status = EDITOR_STATUS_NORMAL;

   if (!text || (len = strlen(text) + 1) == 1) {
      *ptr = NULL;
   } else {
      if (!(*ptr = DosAllocMem(len))) {
	 status = EDITOR_ERROR_OUT_OF_MEM;
      } else {
	 CopyMem(text, *ptr, len);
      }
   }
   return(status);
}
	/* Duplicate text list */

   SHORT
duplicate_text_list(struct Template  *old_tp, struct Template  *new_tp)
{
   struct Node  *node;
   SHORT status = EDITOR_STATUS_NORMAL;

   NewList(&new_tp->tp_TextList);
   for (node = get_head(&old_tp->tp_TextList); node &&
		    status == EDITOR_STATUS_NORMAL; node = get_succ(node)) {
      status = add_template_text_list_entry(new_tp, node->ln_Name);
   }
   return(status);
}
	/* Build template text list from given text array */

   SHORT
build_template_text_list(struct Template  *tp, BYTE **text_array)
{
   BYTE  *text;
   SHORT status = EDITOR_STATUS_NORMAL;

   NewList(&tp->tp_TextList);
   for (text = *text_array; text && status == EDITOR_STATUS_NORMAL;
						     text = *++text_array) {
      status = add_template_text_list_entry(tp, text);
   }
   if (status != EDITOR_STATUS_NORMAL) {
      free_template_text_list(tp);
   }
   return(status);
}
	/* Build text list entry */

   struct Node *
build_text_list_entry(BYTE *text)
{
   struct Node  *node;

   if (node = AllocMem((LONG)sizeof(struct Node), (LONG)MEMF_PUBLIC |
							      MEMF_CLEAR)) {
      if (!(node->ln_Name = DosAllocMem((LONG)(strlen(text) + 1)))) {
	 FreeMem(node, (LONG)sizeof(struct Node));
	 node = NULL;
      } else {
	 strcpy(node->ln_Name, text);
      }
   }
   return(node);
}
	/* Add text entry to template text list */

   SHORT
add_template_text_list_entry(struct Template  *tp, BYTE *text)
{
   struct Node  *node;
   SHORT status = EDITOR_STATUS_NORMAL;

   if (!(node = build_text_list_entry(text))) {
      status = EDITOR_ERROR_OUT_OF_MEM;
   } else {
      AddTail(&tp->tp_TextList, node);
   }
   return(status);
}
	/* Free template text list */

   VOID
free_template_text_list(struct Template  *tp)
{
   struct List  *list = &tp->tp_TextList;
   struct Node  *node;

   while (node = RemTail(list)) {
      free_text_list_entry(node);
   }
}
	/* Free text list entry */

   VOID
free_text_list_entry(struct Node  *node)
{
   DosFreeMem(node->ln_Name);
   FreeMem(node, (LONG)sizeof(struct Node));
}
	/* Build template text array from template text list */

   SHORT
build_template_text_array(struct Template  *tp)
{
   struct GadgetData  *gd = &tp->tp_Data.tp_GadgetData;
   struct List        *list = &tp->tp_TextList;
   struct Node        *node;
   BYTE   **text_array;
   USHORT count = 0;
   SHORT  status = EDITOR_STATUS_NORMAL;

   /* Count entries in text list */
   for (node = get_head(list); node; node = get_succ(node)) {
      count++;
   }
   if (!(text_array = DosAllocMem((LONG)(count + 1) * sizeof(BYTE *)))) {
      status = EDITOR_ERROR_OUT_OF_MEM;
   } else {
      switch (tp->tp_Type) {
	 case TEMPLATE_TYPE_MX :
	    gd->gd_SpecialData.gd_MXData.gd_MXTextArray = text_array;
	    break;
	 case TEMPLATE_TYPE_CYCLE :
	    gd->gd_SpecialData.gd_CycleData.gd_CycleTextArray = text_array;
	    break;
      }

      /* Fill text array with pointers to text list entries */
      for (node = get_head(list); node && status == EDITOR_STATUS_NORMAL;
						    node = get_succ(node)) {
	 *text_array++ = node->ln_Name;
      }
      *text_array = NULL;   /* mark end of text array */
   }
   return(status);
}
	/* Free template text array */

   VOID
free_template_text_array(struct Template  *tp)
{
   struct GadgetData  *gd = &tp->tp_Data.tp_GadgetData;
   BYTE **text_array;

   switch (tp->tp_Type) {
      case TEMPLATE_TYPE_MX :
	 text_array = gd->gd_SpecialData.gd_MXData.gd_MXTextArray;
	 gd->gd_SpecialData.gd_MXData.gd_MXTextArray = NULL;
	 break;
      case TEMPLATE_TYPE_CYCLE :
	 text_array = gd->gd_SpecialData.gd_CycleData.gd_CycleTextArray;
	 gd->gd_SpecialData.gd_CycleData.gd_CycleTextArray = NULL;
	 break;
      default :
	 text_array = NULL;
	 break;
   }
   DosFreeMem(text_array);
}
	/* Open font with given attribute */

   struct TextFont *
open_font(struct TextAttr  *ta)
{
   struct TextFont  *tf;

   tf = OpenFont(ta);
   if (!tf || tf->tf_YSize != ta->ta_YSize) {
      tf = OpenDiskFont(ta);
   }
   return(tf);
}
	/* Close font */

   VOID
close_font(struct TextFont  *tf)
{
   if (tf) {
      CloseFont(tf);
   }
}
