/*
   ***************************************************************************
   *
   * Datei:
   *      RSysIntuiCtrl.c
   *
   * Inhalt:
   *
   *      --- Globale Routinen ---
   *
   *    APTR LockWindow ( WINDOW *win );
   *    char *gadgetbuff ( GADGET *gad );
   *    int OpenASysWindow ( int (*func )(void ), int kill );
   *    long SetupScreen ( void );
   *    SCREEN *FindFrontPubScr ( SCREEN *activescr );
   *    void AdjustWindowDimensions ( SCREEN *Scr , UWORD WinLeftEdge , UWORD WinTopEdge , UWORD WinWidth , UWORD WinHeight , UWORD *NewWinLeftEdge , UWORD *NewWinTopEdge , UWORD *NewWinWidth , UWORD *NewWinHeight );
   *    void CenterWindow ( SCREEN *scr , UWORD *top , UWORD *left , UWORD width , UWORD height );
   *    void ClearIntuiMsgPort ( WINDOW *wnd );
   *    void CloseASysWindow ( WINDOW **wind , GADGET **windgadlist , MENU **windmenus );
   *    void CloseDownScreen ( void );
   *    void DisableSysRequest ( int disable );
   *    void EmptyListView ( void );
   *    void EnableGadget ( WINDOW *Wnd , GADGET *gad , int on_off );
   *    void InitListView ( WINDOW *wind , GADGET *gad , LIST *list , int top );
   *    void LockMainWindow ( int on );
   *    void makelabelvisible ( GADGET *gad );
   *    void MakePattern ( WINDOW *wind );
   *    void MakeWindowRefresh ( WINDOW *window );
   *    void OpenMainWindow ( void );
   *    void PrintHeader ( enum ListTypes type , char *text );
   *    void PrintInfo ( char *text , int speakit , int waitit );
   *    void PrintStatistics ( void );
   *    void RefreshListView ( void );
   *    void RefreshMainWindowPattern ( void );
   *    void RefreshRastPort ( WINDOW *wind , GADGET **gads , int *gadnum , int cnt , int SaveGad , GADGET *GadgetList );
   *    void RefreshWindowAndGadgets ( WINDOW *wind );
   *    void UnlockWindow ( APTR req );
   *    WORD MyEasyRequest ( WINDOW *wind , UBYTE *title , UBYTE *Gadgets , UBYTE *Body , ...);
   *
   *      --- Lokale  Routinen ---
   *
   *    static void FillGadget ( WINDOW *wind , GADGET *gad , BYTE SaveGad );
   *
   * Bemerkungen:
   *      Intuition Supportroutinen für die Verwaltung der Intuitionobjekte
   *      des Hauptwindows von RSys.
   *      (Aus RSysUtils.c ausgelagert)
   *
   * Erstellungsdatum:
   *      25-Jun-93     Rolf Böhme
   *
   * Änderungen:
   *      25-Jun-93     Rolf Böhme        Erstellung
   *      25-Jun-93     Rolf Böhme        makelabelvisible() hinzugefügt
   *
   ***************************************************************************
 */

#include "RSys.h"
#include "protos.h"

/********************************************************************
 *                                                                  *
 *       ***************** Gadget Routinen *****************        *
 *                                                                  *
 ********************************************************************/

 /*
  * EnableGadget() schaltet ein Gadget auf einem Window ein oder
  * aus
  */
void
EnableGadget (WINDOW * Wnd, GADGET * gad, int on_off)
{
  DPOS;

  GT_SetGadgetAttrs (gad, Wnd, NULL, GA_Disabled, NOT (on_off), TAG_DONE);

  return;
}

void
makelabelvisible (GADGET * gad)
{

  if (gad->GadgetText)
    {
      gad->GadgetText->DrawMode |= JAM2;
      gad->GadgetText->BackPen = 0;
      gad->GadgetText->FrontPen = 1;
    }

  return;
}

 /*
  * gadgetbuff() ermittelt den String, der in einem Stringgadget
  * steht
  */
char *
gadgetbuff (GADGET * gad)
{
  DPOS;

  return ((char *) (((STRINGINFO *) (gad->SpecialInfo))->Buffer));
}

 /*
  * FillGadget() löscht den Hintergrund eines Boolean-Gadgets
  */
static void
FillGadget (WINDOW * wind, GADGET * gad, BYTE SaveGad)
{
  BYTE GadType = (BYTE) gad->GadgetType;
  UWORD pos;

  if (SaveGad)
    pos = RemoveGadget (wind, gad);

  if (GadType == GTYP_STRGADGET)
    EraseRect (wind->RPort, (long) gad->LeftEdge - 2,
	       (long) gad->TopEdge - 1,
	       (long) (gad->LeftEdge + gad->Width + 1),
	       (long) (gad->TopEdge + gad->Height));
  else
    EraseRect (wind->RPort, (long) gad->LeftEdge,
	       (long) gad->TopEdge,
	       (long) (gad->LeftEdge + gad->Width - 1),
	       (long) (gad->TopEdge + gad->Height - 1));

  if (SaveGad)
    AddGadget (wind, gad, (ULONG) pos);

  return;
}

 /*
  * InitListView() initialisiert ein ListView in einem Fenster
  * mit einer anzugebenden Liste. Ist die Liste NULL, wird das
  * ListView systemgemäß mit ~0 initialisiert
  */
void
InitListView (WINDOW * wind, GADGET * gad, LIST * list, int top)
{
  LIST *lvlist = (list != NULL) ? list : (LIST *) (~0);

  DPOS;

  if (list != NULL)
    GT_SetGadgetAttrs (gad, wind, NULL, GTLV_Labels, (~0), TAG_DONE);

  if (top == UNSETLVPOS)
    GT_SetGadgetAttrs (gad, wind, NULL, GTLV_Labels, lvlist, TAG_DONE);
  else
    GT_SetGadgetAttrs (gad, wind,
		       NULL,
		       GTLV_Labels, lvlist,
		       GTLV_Top, top,
		       GTLV_Selected, (~0),
		       TAG_DONE);
}

 /*
  * RefreshListView() erneuert das ListView auf dem Hauptwindow
  */
void
RefreshListView (void)
{
  DPOS;

  InitListView (SysWnd, SysGadgets[GD_ListeLV], &ListeLVList, UNSETLVPOS);
  return;
}

 /*
  * EmptyListView() löscht die Einträge des Haupt-ListViews
  */
void
EmptyListView (void)
{
  DPOS;

  InitListView (SysWnd, SysGadgets[GD_ListeLV], NULL, 0);

  NewList (&ListeLVList);

  RefreshListView ();

  GT_RefreshWindow (SysWnd, NULL);

  return;
}

/********************************************************************
 *                                                                  *
 *       ***************** Window Routinen *****************        *
 *                                                                  *
 ********************************************************************/

 /*
  * LockWindow() öffnet einen Requester der Größe 1x1 und sperrt
  * das Window damit gegen Eingaben
  */
APTR
LockWindow (WINDOW * win)
{
  REQUESTER *req = NULL;

  DPOS;

  if (!win)
    return NULL;

  req = (REQUESTER *) MyAllocVec (sizeof (REQUESTER), MEMF_ANY | MEMF_CLEAR, NO_KILL);
  if (req)
    {
      req->LeftEdge = 1;
      req->TopEdge = 1;
      req->Width = 1;
      req->Height = 1;
      req->Flags = SIMPLEREQ | NOREQBACKFILL;

      Request (req, win);
    }

  return ((APTR) req);
}

 /*
  * UnlockWindow() gibt ein mit LockWindow() gesperrtes Window
  * wieder frei. Es ist dann wieder für Benutzereingaben
  * zugänglich
  */
void
UnlockWindow (APTR req)
{
  DPOS;

  if (req)
    {
      EndRequest ((REQUESTER *) req, ((REQUESTER *) req)->RWindow);
      MyFreeVec (req);

      req = NULL;
    }

  return;
}

void
LockMainWindow (int on)
{
  static APTR req = NULL;

  if (on)
    req = LockWindow (SysWnd);
  else
    {
      UnlockWindow (req);
      RefreshMainWindowPattern ();
      PrintStatistics ();
/*      RefreshList(LastID); */
    }

  return;
}

 /*
  * MakeWindowRefresh() führt die Standard-System-Routinen zur
  * Erneuerung eines Windows aus
  */
void
MakeWindowRefresh (WINDOW * window)
{
  GT_BeginRefresh (window);
  GT_EndRefresh (window, TRUE);

  return;
}

void
MakePattern (WINDOW * wind)
{
  RASTPORT *RP = wind->RPort;

  if (wind != SysWnd && (wind->Flags & WFLG_ZOOMED))
    return;

  if (bgc || bpc)
    {
      SetAfPt (RP, (USHORT *) & bpp, 1L);

      SetAPen (RP, bpc);
      SetBPen (RP, bgc);

      SetDrMd (RP, JAM2);

      RectFill (RP, (long) OffX, (long) OffY,
		(long) wind->Width - Scr->WBorRight,
	    (long) wind->Height - Scr->WBorBottom + 1 - wind->BorderBottom);

      SetAfPt (RP, NULL, NULL);
    }
  else
    {
      SetAPen (RP, 0);
      SetBPen (RP, 0);

      RectFill (RP, (long) OffX, (long) OffY,
		(long) wind->Width - Scr->WBorRight,
	    (long) wind->Height - Scr->WBorBottom + 1 - wind->BorderBottom);
    }

  return;
}

void
RefreshWindowAndGadgets (WINDOW * wind)
{
  RefreshGadgets (wind->FirstGadget, wind, NULL);

  RefreshWindowFrame (wind);
  GT_RefreshWindow (wind, NULL);

  return;
}

 /*
  * RefreshRastPort() malt das Hintergrundmuster und erneuert
  * die Gadgets und deren Hintergrund
  */
void
RefreshRastPort (WINDOW * wind, GADGET ** gads,
		 int *gadnum, int cnt, int SaveGad,
		 GADGET * GadgetList)
{
  GADGET *gad;
  int i;

  if (wind != SysWnd && (wind->Flags & WFLG_ZOOMED))
    return;

  MakePattern (wind);

  if (bgc || bpc)
    {
      for (i = 0; i < cnt; i++)
	FillGadget (wind, gads[gadnum[i]], (BYTE) SaveGad);

      for (gad = gads[0]; gad; gad = gad->NextGadget)
	if (gad->GadgetText)
	  {
	    int pixlen = IntuiTextLength (gad->GadgetText);
	    int x = gad->LeftEdge + gad->GadgetText->LeftEdge - 3, y = gad->TopEdge + gad->GadgetText->TopEdge - 2,
	      w = pixlen + 6, h = gad->GadgetText->ITextFont->ta_YSize + 4;

	    EraseRect (wind->RPort, (long) x, (long) y, (long) (x + w - 1), (long) (y + h - 1));

	    DrawBevelBox (wind->RPort, x, y, w, h,
			  GTBB_Recessed, TRUE,
			  GT_VisualInfo, VisualInfo,
			  TAG_DONE);
	  }
    }

  if (GadgetList)
    AddGList (wind, GadgetList, -1, -1, NULL);

  RefreshWindowAndGadgets (wind);

  if (Flags.autofront)
    {
      WindowToFront (wind);
      ActivateWindow (wind);
    }

  return;
}

 /*
  * RefreshMainWindowPattern() erneuert das Patternmuster
  * des Hauptfensters von RSys
  */
void
RefreshMainWindowPattern (void)
{
  int gl[] =
  {GD_ListeLV, GD_TextHeader, GD_InfoMsgGad};

  if (SysWnd)
    RefreshRastPort (SysWnd, SysGadgets, gl, 3, TRUE, NULL);

  return;
}

 /*
  * ClearIntuiMsgPort() beantwortet alle anliegenden Messages
  * eines Windows
  */
void
ClearIntuiMsgPort (WINDOW * wnd)
{
  INTUIMESSAGE *message;

  DPOS;

  while (message = (INTUIMESSAGE *) GT_GetIMsg (wnd->UserPort))
    GT_ReplyIMsg (message);

  return;
}

 /*
  * OpenMainWindow() öffnet das Hauptffenster
  */
void
OpenMainWindow (void)
{
  int OpenSysWindow (void);

  int err;

  DPOS;

  if (!(err = SetupScreen ()))
    {
      OpenASysWindow (OpenSysWindow, KILL);
      return;
    }

  if (err == 1)
    ErrorHandle ((char *) namebuffer, SCREEN_ERR, LOCK_FAIL, KILL);
  else
    ErrorHandle ((char *) "Visual info", SCREEN_ERR, INFO_FAIL, KILL);

  return;
}

 /*
  * CloseASysWindow() schließt ein von RSys verwaltetes Window
  */
void
CloseASysWindow (WINDOW ** wind, GADGET ** windgadlist, MENU ** windmenus)
{
  DPOS;

  if (!(*wind))
    return;

  if (windmenus && *windmenus)
    {
      ClearMenuStrip (*wind);
      FreeMenus (*windmenus);
      *windmenus = NULL;
    }

  if (wind && *wind)
    {
      CloseWindow (*wind);
      *wind = NULL;
    }

  if (windgadlist && *windgadlist)
    {
      FreeGadgets (*windgadlist);
      *windgadlist = NULL;
    }

  return;
}

 /*
  * OpenASysWindow() öffnet ein Window mit einer
  * vorzugebenden Funktion und mit einer allgemeinen
  * Fehlerbehandlung
  */
int
OpenASysWindow (int (*func) (void), int kill)
{
  ULONG failed = (*func) ();

  DPOS;

  switch (failed)
    {
    case 1L:
      ErrorHandle ("GadTools-Context", OBJECT_CONTEXT_ERR, CREATE_FAIL, kill);
      break;

    case 2L:
      ErrorHandle ("CreateGadget()", GADGET_ERR, CREATE_FAIL, kill);
      break;

    case 3L:
      ErrorHandle ("LayoutMenu()", MENU_ERR, CREATE_FAIL, kill);
      break;

    case 4L:
      ErrorHandle ("OpenWindowTags()", WINDOW_ERR, OPEN_FAIL, kill);
      break;
    }

  return (failed ? FALSE : TRUE);
}

 /*
  * CenterWindow() ermittelt die Fensterposition, um das
  * Fenster zentriert auf einem Screen erscheinen zu lassen
  */
void
CenterWindow (SCREEN * scr, UWORD * top, UWORD * left,
	      UWORD width, UWORD height)
{
  WORD LE, TE;
  WORD restwidth = scr->Width - width, restheight = scr->Height - height;

  DPOS;

  if (scr)
    {
      LE = (Flags.mousewindow ? scr->MouseX : (scr->Width >> 1)) - (width >> 1);
      TE = (Flags.mousewindow ? scr->MouseY : (scr->Height >> 1)) - (height >> 1);

      *left = (LE < 0) ? (UWORD) 0 : ((LE > restwidth) ? restwidth : LE);
      *top = (TE < 0) ? (UWORD) 0 : ((TE > restheight) ? restheight : TE);
    }

  return;
}

void
AdjustWindowDimensions (SCREEN * Scr,
			UWORD WinLeftEdge, UWORD WinTopEdge,
			UWORD WinWidth, UWORD WinHeight,
			UWORD * NewWinLeftEdge, UWORD * NewWinTopEdge,
			UWORD * NewWinWidth, UWORD * NewWinHeight)
{
  DPOS;

  ComputeFont (Scr, WinWidth, WinHeight);

  *NewWinWidth = compute ((UWORD) 0, FontX, (int) WinWidth);
  *NewWinHeight = compute ((UWORD) 0, FontY, (int) WinHeight);

  if ((WinLeftEdge + *NewWinWidth + OffX + Scr->WBorRight) > Scr->Width)
    *NewWinLeftEdge = Scr->Width - *NewWinWidth;

  if ((WinTopEdge + *NewWinHeight + OffY + Scr->WBorBottom) > Scr->Height)
    *NewWinTopEdge = Scr->Height - *NewWinHeight;

  *NewWinWidth = compute ((UWORD) (OffX + Scr->WBorRight), FontX, (int) WinWidth);
  *NewWinHeight = compute ((UWORD) (OffY + Scr->WBorBottom), FontY, (int) WinHeight);

  CenterWindow (Scr, NewWinTopEdge, NewWinLeftEdge, *NewWinWidth, *NewWinHeight);

  return;
}


/********************************************************************
 *                                                                  *
 *       ***************** Screen Routinen *****************        *
 *                                                                  *
 ********************************************************************/

 /*
  * Die Funktion FindFrontPubScr() ermittelt
  * bezüglich des aktuellen Screens, auf dem das
  * Hauptfenster geöffnet wurde, den nächsten Public
  * screen und gibt den Zeiger auf diesen zurück,
  * falls dieser ungleich dem aktuellen und zugleich
  * der vorderste Screen auf dem Bildschirm ist.
  */
SCREEN *
FindFrontPubScr (SCREEN * activescr)
{
  char newnamebuffer[MAXPUBSCREENNAME + 1];
  UBYTE *test;
  SCREEN *NewScr;

  DPOS;
  /*
   * Der Name des aktuellen Screens, auf dem RSys
   * geöffnet wurde, wird gemerkt.
   */
  strncpy (newnamebuffer, (char *) namebuffer, MAXPUBSCREENNAME);

  /*
   * Der Zeiger des neuen Screens wird initialisiert
   * und der nächst Public screen ermittelt.
   */
  NewScr = NULL;
  test = NextPubScreen (activescr, namebuffer);

  /*
   * Solange der neue Screen nicht der vorderste
   * Screen und nicht der aktuelle ist, und der neue
   * Screen erfolgreich ermittelt werden konnte, wird
   * dieser neue getestet. Im Erfolgsfall wird ein
   * Zeiger auf diesen neuen Screen zurückgegeben.
   */
  while ((NewScr != IntuitionBase->FirstScreen) && (NewScr != activescr) && test)
    {
      NewScr = LockPubScreen (namebuffer);

      if ((NewScr == IntuitionBase->FirstScreen) && (NewScr != activescr))
	{
	  UnlockPubScreen (NULL, NewScr);
	  return (NewScr);
	}

      UnlockPubScreen (NULL, NewScr);

      test = NextPubScreen (NewScr, namebuffer);
    }

  /*
   * Wenn das Unterprogramm bis hierher kommt, konnte
   * kein weiterer Public screen erkannt werden. Der
   * gemerkte Screen name wird zurückkopiert und der
   * Zeiger auf den aktiven Screen zurückgegeben.
   */
  strncpy ((char *) namebuffer, newnamebuffer, MAXPUBSCREENNAME);

  return (activescr);
}

 /*
  * SetupScreen() ermittelt eine Zeiger auf den vordersten
  * Screen. Ist der vorderste Screen kein PublicScreen,
  * wird der WorkBench-Screen als Default-Screen genommen.
  */
long
SetupScreen (void)
{

  DPOS;

  (void) FindFrontPubScr (lastpubscreen);

  if (NOT (Scr = LockPubScreen (namebuffer)))
    {
      strcpy ((char *) namebuffer, "Workbench");
      if (NOT (Scr = LockPubScreen (namebuffer)))
	return (1L);
    }

  ComputeFont (Scr, (UWORD) 0, (UWORD) 0);

  if (NOT (VisualInfo = GetVisualInfo (Scr, TAG_DONE)))
    return (2L);

  lastpubscreen = Scr;

  return NULL;
}

 /*
  * CloseDownScreen() gibt den Screen frei, auf den ein
  * RSys-Window geöffnet wurde.
  */
void
CloseDownScreen (void)
{
  DPOS;

  if (VisualInfo)
    {
      FreeVisualInfo (VisualInfo);
      VisualInfo = NULL;
    }

  if (Scr)
    {
      UnlockPubScreen (NULL, Scr);
      Scr = NULL;
    }

  return;
}


/********************************************************************
 *                                                                  *
 *    ***************** Informations Routinen *****************     *
 *                                                                  *
 ********************************************************************/

 /*
  * DisableSysRequest() unterdrückt die Anzeige von
  * Systemrequestern, die beispielsweise nach einem Zugriff auf
  * einen nicht existierenden Datenträger erscheinen
  */
void
DisableSysRequest (int disable)
{
  static APTR wind;
  PROCESS *p = (PROCESS *) FindTask (NULL);

  DPOS;

  if (disable)
    {
      wind = (APTR) p->pr_WindowPtr;
      p->pr_WindowPtr = (APTR) (-1);
    }
  else
    p->pr_WindowPtr = wind;

  return;
}



 /*
  * PrintHeader() gibt einen Text im Titelfeld über dem
  * Haupt-ListView aus
  */
void
PrintHeader (enum ListTypes type, char *text)
{
  DPOS;

  LastID = type;

  GT_SetGadgetAttrs (SysGadgets[GD_TextHeader], SysWnd,
		     NULL,
       GTTX_Text, (UBYTE *) (NOT (text) ? EntryAttr[type].ea_header : text),
		     TAG_DONE);

  return;
}

 /*
  * PrintInfo() gibt einen Text im Messagefeld vom Hauptfenster
  * aus. Falls der Sprachmodus aktiviert ist und der Text
  * gesprochen werden soll, wird er zusätzlich auf dem
  * Narrator-Device ausgegeben
  */
void
PrintInfo (char *text, int speakit, int waitit)
{
  static char help[BUFSIZE];
  int i, len = strlen (text), fill = ((BUFSIZE - len) >> 1);

  DPOS;

  if (!SysWnd || SysWnd->FirstRequest)
    return;

  for (i = 0; i < fill; i++)
    help[i] = ' ';

  help[fill] = STRINGEND;

  strcat (help, text);

  GT_SetGadgetAttrs (SysGadgets[GD_InfoMsgGad], SysWnd,
		     NULL,
		     GTTX_Text, (UBYTE *) help,
		     TAG_DONE);

  if (NOT (Flags.fastmode))
    WaitTOF ();

  if (Flags.speakmode && speakit)
    Speak (help);

  if (waitit != 0)
    Delay (waitit);

  return;
}

 /*
  * PrintStatistics() gibt für bestimmte Listen eine
  * Zusammenfasung (Anzahl der ermittelten Einträge) aus
  */

/*
 * hacked by GMD
 */

void
PrintStatistics (void)
{
  char help[BUFSIZE];
  char *type = EntryAttr[LastID].ea_type;

  DPOS;

  help[0] = '\0';

  if (!SysWnd || SysWnd->FirstRequest)
    return;

  if (countentries == 0)
    {
      sprintf (help, "No %s entries read", type);
    }
  else if (EntryAttr[LastID].ea_counted == EA_C)
    {
      sprintf (help, "%ld %s entries read", countentries, type);
    }
  else if (EntryAttr[LastID].ea_counted == EA_C_HELP)
    {
      strncpy (help, gbuf, BUFSIZE);
      help[BUFSIZE - 1] = '\0';	/* just in sace */
    }
#if 0
  else if (EntryAttr[LastID].ea_counted == EA_NOTC)
    {
      sprintf (help, "done");
    }
#endif

  PrintInfo (help, SPEAK, 0);

  RefreshListView ();

  return;
}

 /*
  * MyEasyRequest() erzeugt nach Vorgaben einen
  * System-Standard-Requester
  */
WORD
MyEasyRequest (WINDOW * wind, UBYTE * title,
	       UBYTE * Gadgets, UBYTE * Body,...)
{
  EASYSTRUCT Easy;
  WORD Result;
  va_list VarArgs;
  APTR req;

  DPOS;

  Easy.es_StructSize = sizeof (EASYSTRUCT);

  Easy.es_Flags = NULL;
  Easy.es_Title = title;
  Easy.es_TextFormat = Body;
  Easy.es_GadgetFormat = Gadgets;

  req = LockWindow (wind);

  va_start (VarArgs, Body);
  Result = EasyRequestArgs (wind, &Easy, NULL, VarArgs);
  va_end (VarArgs);

  UnlockWindow (req);

  return Result;
}
