/* $Revision Header *** Header built automatically - do not edit! ***********
 *
 *	(C) Copyright 1991 by Torsten Jürgeleit
 *
 *	Name .....: requester.c
 *	Created ..: Thursday 19-Dec-91 18:55:19
 *	Revision .: 1
 *
 *	Date        Author                 Comment
 *	=========   ====================   ====================
 *	28-Dec-91   Torsten Jürgeleit      auto requester with body text string
 *                                         (with '\n' as new line indicator)
 *                                         instead of text array
 *	19-Dec-91   Torsten Jürgeleit      Created this file!
 *
 ****************************************************************************
 *
 *	Requester support routines
 *
 * $Revision Header ********************************************************/

	/* Includes */

#include <exec/types.h>
#include <exec/memory.h>
#include <graphics/text.h>
#include <intuition/intuition.h>
#include <intuition/screens.h>
#include <functions.h>
#include <libraries/memwatch.h>		/* AFTER functions.h */
#include <string.h>
#include <ctype.h>
#include "/render/render.h"
#include "/texts/texts.h"
#include "/borders/borders.h"
#include "/gadgets/gadgets.h"
#include "/gadgets/imports.h"
#include "/language/language.h"
#include "/pointer/pointer.h"
#include "requester.h"

	/* Defines for auto request */

#define AUTO_REQ_DETAIL_PEN	0
#define AUTO_REQ_BLOCK_PEN	1

#define AUTO_REQ_IDCMP_FLAGS	(GADGET_IDCMP_FLAGS_BUTTON | pos_idcmp_flags | neg_idcmp_flags)
#define AUTO_REQ_FLAGS		(WINDOWDRAG | WINDOWDEPTH | SMART_REFRESH | NOCAREREFRESH | RMBTRAP | ACTIVATE)
#define AUTO_REQ_HORIZ_OFFSET	20
#define AUTO_REQ_VERT_OFFSET	10
#define AUTO_REQ_VERT_SPACING	2

#define AUTO_REQ_GADGET_HORIZ_BORDER_OFFSET	8
#define AUTO_REQ_GADGET_VERT_BORDER_OFFSET	4
#define AUTO_REQ_GADGET_HORIZ_SPACING		20
#define AUTO_REQ_GADGET_VERT_SPACING		10

	/* Defines for requester */

#define REQ_DETAIL_PEN		0
#define REQ_BLOCK_PEN		1
#define REQ_IDCMP_FLAGS		GADGET_IDCMP_FLAGS_ALL
#define REQ_FLAGS		(SMART_REFRESH | NOCAREREFRESH | RMBTRAP | ACTIVATE)

	/* Externals */

IMPORT struct IntuitionBase  *IntuitionBase;

	/* Static prototypes */

USHORT remove_visible_gadget_lists(struct Window  *win,
						     struct MinList  *list);
VOID   display_visible_gadget_lists(struct Window  *win,
						     struct MinList  *list);
	/* Static pragmas */

#pragma regcall(remove_visible_gadget_lists(a0,a1))
#pragma regcall(display_visible_gadget_lists(a0,a1))

	/* Display auto request */

   BOOL
auto_request(struct Window  *req_win, BYTE *title, BYTE *body_text,
		       BYTE *pos_text, BYTE *neg_text, LONG pos_idcmp_flags,
	 LONG neg_idcmp_flags, USHORT req_flags, BYTE **language_text_array)
{
   BOOL result = FALSE;

   if (body_text && (pos_text || neg_text)) {
      struct RenderInfo  *ri;
      struct Menu        *menu;
      struct Screen      *screen;
      struct MinList     list;
      ULONG flags;

      if (req_win) {

	 /* Remove gadgets and menu from given window */
	 remove_visible_gadget_lists(req_win, &list);
	 if (menu = req_win->MenuStrip) {
	    ClearMenuStrip(req_win);
	 }
      }

      /* Get render info */
      screen = (req_win ? req_win->WScreen : NULL);
      flags  = RENDER_INFO_FLAG_INNER_WINDOW | (req_flags &
		  AUTO_REQ_FLAG_BACK_FILL ? RENDER_INFO_FLAG_BACK_FILL : 0);
      if (ri = get_render_info(screen, (USHORT)flags)) {
	 BYTE *text;
	 LONG text_len;

	 /* Make copy of body text */
	 body_text = get_language_text(body_text, language_text_array);
	 text_len  = strlen(body_text) + 2;
	 if (text = AllocMem(text_len, (LONG)MEMF_PUBLIC)) {
	    struct TextAttr    *ta = &ri->ri_TextAttr;
	    struct GadgetData  gadget_data[3], *gd = &gadget_data[0];
	    struct GadgetList  *gl;
	    USHORT count, len1, len2, width1, width2, width, height,
		   gad_width, gad_height, num_gadgets;
	    BYTE   *ptr = text + 1, *line = text;

	    strcpy(ptr, body_text);
	    *(ptr + text_len - 2) = '\0';

	    /* Mark mark/count lines in body text string */
	    width1 = 0;
	    count  = 1;
	    while ((ptr = strchr(ptr, '\\')) && toupper(*(ptr + 1)) == 'N') {

	       /* Save line length and mark end of line */
	       *line = ptr - (line + 1);
	       *ptr  = '\0';

	       /* Calc max width of body text */
	       if ((len1 = print_text(ri, NULL, line + 1, 0, 0,
			       TEXT_DATA_TYPE_TEXT, TEXT_DATA_FLAG_NO_PRINT,
							    ta)) > width1) {
		  width1 = len1;
	       }

	       /* Increment pointers and line counter */
	       line = ptr + 1;
	       ptr += 2;
	       count++;
	    }

	    /* Prepare last line of body text */
	    *line = strlen(line + 1);
	    if ((len1 = print_text(ri, NULL, line + 1, 0, 0,
			       TEXT_DATA_TYPE_TEXT, TEXT_DATA_FLAG_NO_PRINT,
							    ta)) > width1) {
	       width1 = len1;
	    }

	    /* Calc max width of gadgets */
	    num_gadgets = 2;
	    if (!pos_text) {
	       len1        = 0;
	       num_gadgets = 1;
	    } else {
	       len1 = print_text(ri, NULL, get_language_text(pos_text,
			    language_text_array), 0, 0, TEXT_DATA_TYPE_TEXT,
					       TEXT_DATA_FLAG_NO_PRINT, ta);
	    }
	    if (!neg_text) {
	       len2        = 0;
	       num_gadgets = 1;
	    } else {
	       len2 = print_text(ri, NULL, get_language_text(neg_text,
			    language_text_array), 0, 0, TEXT_DATA_TYPE_TEXT,
					       TEXT_DATA_FLAG_NO_PRINT, ta);
	    }
	    gad_width  = (len1 > len2 ? len1 : len2) +
				    2 * AUTO_REQ_GADGET_HORIZ_BORDER_OFFSET;
	    gad_height = ta->ta_YSize +
				     2 * AUTO_REQ_GADGET_VERT_BORDER_OFFSET;
	    width2     = num_gadgets * gad_width + (num_gadgets == 2 ?
					 AUTO_REQ_GADGET_HORIZ_SPACING : 0);
	    /* Calc width and height of requester window */
	    width  = (width1 > width2 ? width1 : width2) +
						  2 * AUTO_REQ_HORIZ_OFFSET;
	    height = count * (ta->ta_YSize + AUTO_REQ_VERT_SPACING) +
				 AUTO_REQ_GADGET_VERT_SPACING + gad_height +
						   2 * AUTO_REQ_VERT_OFFSET;
	    /* Init gadget data and create gadget list */
	    flags = (req_flags & AUTO_REQ_FLAG_HOTKEY ?
					       GADGET_DATA_FLAG_HOTKEY : 0);
	    if (pos_text) {
	       gd->gd_Type     = GADGET_DATA_TYPE_BUTTON;
	       gd->gd_Flags    = flags |
			       (req_flags & AUTO_REQ_FLAG_MOVE_POINTER_POS ?
					 GADGET_DATA_FLAG_MOVE_POINTER : 0);
	       gd->gd_LeftEdge = (num_gadgets == 2 ? AUTO_REQ_HORIZ_OFFSET :
						   (width - gad_width) / 2);
	       gd->gd_TopEdge  = height - (gad_height + AUTO_REQ_VERT_OFFSET);
	       gd->gd_Width    = gad_width;
	       gd->gd_Height   = gad_height;
	       gd->gd_Text     = pos_text;
	       gd->gd_TextAttr = ta;
	       gd++;
	    }
	    if (neg_text) {
	       gd->gd_Type     = GADGET_DATA_TYPE_BUTTON;
	       gd->gd_Flags    = flags |
			       (req_flags & AUTO_REQ_FLAG_MOVE_POINTER_NEG ?
					 GADGET_DATA_FLAG_MOVE_POINTER : 0);
	       gd->gd_LeftEdge = (num_gadgets == 2 ? width - (gad_width +
			  AUTO_REQ_HORIZ_OFFSET) : (width - gad_width) / 2);
	       gd->gd_TopEdge  = height - (gad_height + AUTO_REQ_VERT_OFFSET);
	       gd->gd_Width    = gad_width;
	       gd->gd_Height   = gad_height;
	       gd->gd_Text     = neg_text;
	       gd->gd_TextAttr = ta;
	       gd++;
	    }
	    gd->gd_Type = INTUISUP_DATA_END;
	    if (gl = create_gadgets(ri, &gadget_data[0], 0, 0,
						     language_text_array)) {
	       struct NewWindow  new_win, *nw = &new_win;
	       struct Window     *win;

	       /* Init and open requester window */
	       nw->LeftEdge    = 0;
	       nw->TopEdge     = 0;
	       nw->Width       = width;
	       nw->Height      = height;
	       nw->DetailPen   = AUTO_REQ_DETAIL_PEN;
	       nw->BlockPen    = AUTO_REQ_BLOCK_PEN;
	       nw->IDCMPFlags  = AUTO_REQ_IDCMP_FLAGS;
	       nw->Flags       = AUTO_REQ_FLAGS;
	       nw->FirstGadget = NULL;
	       nw->CheckMark   = NULL;
	       nw->Title       = (UBYTE *)(title ? get_language_text(title,
				 language_text_array) :	" System Request ");
	       nw->Screen      = screen;
	       nw->BitMap      = NULL;
	       nw->MinWidth    = 0;
	       nw->MinHeight   = 0;
	       nw->MaxWidth    = 0;
	       nw->MaxHeight   = 0;
	       nw->Type        = (screen ? screen->Flags & SCREENTYPE :
							      WBENCHSCREEN);
	       flags = (req_flags & AUTO_REQ_FLAG_RENDER_PENS ?
					  OPEN_WINDOW_FLAG_RENDER_PENS : 0);
	       if (win = open_window(ri, nw, (USHORT)flags)) {
		  struct MsgPort  *up = win->UserPort;
		  struct Screen   *front_screen;
		  USHORT left_edge, top_edge;
		  LONG   ilock;
		  BOOL   keepon = TRUE;

		  /* Display texts and gadgets */
		  line      = text;
		  left_edge = AUTO_REQ_HORIZ_OFFSET;
		  top_edge  = AUTO_REQ_VERT_OFFSET;
		  flags     = (req_flags & AUTO_REQ_FLAG_TEXT_CENTER ?
						TEXT_DATA_FLAG_CENTER : 0) |
				    (req_flags & AUTO_REQ_FLAG_TEXT_COLOR2 ?
						 TEXT_DATA_FLAG_COLOR2 : 0);
		  while (count--) {
		     print_text(ri, win, line + 1, left_edge, top_edge,
				    TEXT_DATA_TYPE_TEXT, (USHORT)flags, ta);
		     line     += *line + 2;
		     top_edge += ta->ta_YSize + AUTO_REQ_VERT_SPACING;
		  }
		  display_gadgets(win, gl);

		  /* Save current font scren and bring our screen to front */
		  ilock = LockIBase((LONG)NULL);
		  front_screen = IntuitionBase->FirstScreen;
		  UnlockIBase(ilock);
		  ScreenToFront(win->WScreen);

		  /* Beep if necessary */
		  if (req_flags & AUTO_REQ_FLAG_BEEP) {
		     DisplayBeep(NULL);
		  }

		  /* Wait for gadget or other IDCMP action */
		  do {
		     struct IntuiMessage  *msg;

		     WaitPort(up);
		     while (msg = get_msg(up)) {
			ULONG class = msg->Class;

			if (class == ISUP_ID) {
			   if (pos_text && msg->Code == 0) {
			      result = TRUE;
			   }
			   keepon = FALSE;
			} else {
			   if (pos_text && (class & pos_idcmp_flags)) {
			      result = TRUE;
			      keepon = FALSE;
			   } else {
			      if (neg_text && (class & neg_idcmp_flags)) {
				 keepon = FALSE;
			      }
			   }
			}
			reply_msg(msg);
		     }
		  } while (keepon == TRUE);
		  remove_gadgets(gl);
		  close_window(win, FALSE);

		  /* Bring old screen back to front */
		  ilock = LockIBase((LONG)NULL);
		  if (IntuitionBase->FirstScreen == front_screen) {
		     front_screen = NULL;
		  }
		  UnlockIBase(ilock);
		  if (front_screen) {
		     ScreenToFront(front_screen);
		  }
	       }
	       free_gadgets(gl);
	    }
	    FreeMem(text, text_len);
	 }
	 free_render_info(ri);
      }
      if (req_win) {

	 /* Enable gadgets and menu for given window */
	 display_visible_gadget_lists(req_win, &list);
	 if (menu) {
	    SetMenuStrip(req_win, menu);
	 }
      }
   }
   return(result);
}
	/* Display requester on given window */

   struct RequesterList *
display_requester(struct Window  *req_win, struct RequesterData  *rd,
						 BYTE **language_text_array)
{
   if (req_win && rd && rd->rd_Gadgets) {
      struct RequesterList  *rl;
      USHORT rd_flags = rd->rd_Flags;

      /* Alloc requester list and remove visible gadget list from window */
      if (rl = AllocMem((LONG)sizeof(struct RequesterList),
					  (LONG)MEMF_PUBLIC | MEMF_CLEAR)) {
	 struct Screen      *screen;
	 struct RenderInfo  *ri;
	 USHORT flags;

	 /* Remove gadgets and menu from given window */
	 remove_visible_gadget_lists(req_win, &rl->rl_VisibleGadgetLists);
	 if (rl->rl_Menu = req_win->MenuStrip) {
	    ClearMenuStrip(req_win);
	 }

	 /* Get render info */
	 screen = req_win->WScreen;
	 flags  = (rd_flags & REQ_DATA_FLAG_INNER_WINDOW ?
					RENDER_INFO_FLAG_INNER_WINDOW : 0) |
		  (rd_flags & REQ_DATA_FLAG_BACK_FILL ?
					   RENDER_INFO_FLAG_BACK_FILL : 0) |
		  (rd_flags & REQ_DATA_FLAG_AVAIL_FONTS ?
					  RENDER_INFO_FLAG_AVAIL_FONTS : 0);
	 if (ri = get_render_info(screen, flags)) {
	    struct GadgetList  *gl;

	    /* Init gadgets */
	    if (gl = create_gadgets(ri, rd->rd_Gadgets, 0, 0,
						     language_text_array)) {
	       struct NewWindow  new_win, *nw = &new_win;
	       struct Window     *win;

	       /* Save requester list ptr */
	       gl->gl_RequesterList = rl;

	       /* Init and open requester window */
	       nw->LeftEdge    = rd->rd_LeftEdge;
	       nw->TopEdge     = rd->rd_TopEdge;
	       nw->Width       = rd->rd_Width;
	       nw->Height      = rd->rd_Height;
	       nw->DetailPen   = REQ_DETAIL_PEN;
	       nw->BlockPen    = REQ_BLOCK_PEN;
	       nw->IDCMPFlags  = NULL;   /* shared user port !!! */
	       nw->Flags       = REQ_FLAGS |
		   (rd_flags & REQ_DATA_FLAG_DRAG_GADGET ? WINDOWDRAG : 0) |
		  (rd_flags & REQ_DATA_FLAG_DEPTH_GADGET ? WINDOWDEPTH : 0);
	       nw->FirstGadget = NULL;
	       nw->CheckMark   = NULL;
	       nw->Title       = (UBYTE *)(rd->rd_Title ?
		      get_language_text(rd->rd_Title, language_text_array) :
							     " Requester ");
	       nw->Screen      = screen;
	       nw->BitMap      = NULL;
	       nw->MinWidth    = 0;
	       nw->MinHeight   = 0;
	       nw->MaxWidth    = 0;
	       nw->MaxHeight   = 0;
	       nw->Type        = (screen ? screen->Flags & SCREENTYPE :
							      WBENCHSCREEN);
	       flags = (rd_flags & REQ_DATA_FLAG_RENDER_PENS ?
					 OPEN_WINDOW_FLAG_RENDER_PENS : 0) |
		       (rd_flags & REQ_DATA_FLAG_CENTER ?
					OPEN_WINDOW_FLAG_CENTER_WINDOW : 0);
	       if (win = open_window(ri, nw, flags)) {

		  /* Enable shared user port */
		  win->UserPort = req_win->UserPort;
		  ModifyIDCMP(win, REQ_IDCMP_FLAGS);

		  /* Display texts, borders and gadgets */
		  display_texts(ri, win, rd->rd_Texts, 0, 0,
						       language_text_array);
		  display_borders(ri, win, rd->rd_Borders, 0, 0);
		  display_gadgets(win, gl);

		  /* Init and return requester list */
		  rl->rl_RenderInfo = ri;
		  rl->rl_Window     = req_win;
		  rl->rl_ReqWindow  = win;
		  rl->rl_GadgetList = gl;
		  rl->rl_ID         = ISUP_ID;
		  return(rl);
	       }
	       free_gadgets(gl);
	    }
	    free_render_info(ri);
	 }
	 FreeMem(rl, (LONG)sizeof(struct RequesterList));
      }
   }
   return(NULL);
}
	/* Remove given requester */

   VOID
remove_requester(struct RequesterList  *rl)
{
   if (rl && rl->rl_ID == ISUP_ID) {
      remove_gadgets(rl->rl_GadgetList);
      free_gadgets(rl->rl_GadgetList);
      close_window(rl->rl_ReqWindow, TRUE);   /* shared user port !!! */
      free_render_info(rl->rl_RenderInfo);

      /* Enable gadgets and menu for given window */
      display_visible_gadget_lists(rl->rl_Window, &rl->rl_VisibleGadgetLists);
      if (rl->rl_Menu) {
	 SetMenuStrip(rl->rl_Window, rl->rl_Menu);
      }
      FreeMem(rl, (LONG)sizeof(struct RequesterList));
   }
}
	/* Remove visible gadget lists from given window and show busy pointer */

   STATIC USHORT
remove_visible_gadget_lists(struct Window  *win, struct MinList  *list)
{
   struct GadgetList  *gl;
   USHORT count = 0;

   NewList((struct List *)list);
   while (gl = get_first_gadget_list(win)) {
      remove_gadgets(gl);
      AddTail((struct List *)list, (struct Node *)&gl->gl_MinNode);
      count++;
   }
   change_mouse_pointer(win, NULL);
   return(count);
}
	/* Display visible gadget lists on given window and restore normal pointer */

   STATIC VOID
display_visible_gadget_lists(struct Window  *win, struct MinList  *list)
{
   struct GadgetList  *gl;

   while (gl = (struct GadgetList *)RemHead((struct List *)list)) {
      display_gadgets(win, gl);
   }
   restore_mouse_pointer(win);
}
