/*
***************************************************************************
*
* Datei:
*	  RSysIntuiCtrl.c
*
* Inhalt:
*
*      --- Globale Routinen ---
*
*    APTR LockWindow ( struct Window *win );
*    char *gadgetbuff ( struct Gadget *gad );
*    int OpenASysWindow ( int (*func )(void ), int kill );
*    long SetupScreen ( void );
*    struct Screen *FindFrontPubScr ( struct Screen *activescr );
*    void AdjustWindowDimensions ( struct Screen *Scr , UWORD WinLeftEdge , UWORD WinTopEdge , UWORD WinWidth , UWORD WinHeight , UWORD *NewWinLeftEdge , UWORD *NewWinTopEdge , UWORD *NewWinWidth , UWORD *NewWinHeight );
*    void CenterWindow ( struct Screen *scr , UWORD *top , UWORD *left , UWORD width , UWORD height );
*    void ClearIntuiMsgPort ( struct Window *wnd );
*    void CloseASysWindow ( struct Window **wind , struct Gadget **windgadlist , struct Menu **windmenus );
*    void CloseDownScreen ( void );
*    void DisableSysRequest ( int disable );
*    void EmptyListView ( void );
*    void EnableGadget ( struct Window *Wnd , struct Gadget *gad , int on_off );
*    void InitListView ( struct Window *wind , struct Gadget *gad , struct List *list , int top );
*    void LockMainWindow ( int on );
*    void makelabelvisible ( struct Gadget *gad );
*    void MakePattern ( struct Window *wind );
*    void MakeWindowRefresh ( struct 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 ( struct Window *wind , struct Gadget **gads , int *gadnum , int cnt , int SaveGad , struct Gadget *GadgetList );
*    void RefreshWindowAndGadgets ( struct Window *wind );
*    void UnlockWindow ( APTR req );
*    WORD MyEasyRequest ( struct Window *wind , UBYTE *title , UBYTE *Gadgets , UBYTE *Body , ...);
*
*      --- Lokale  Routinen ---
*
*    static void FillGadget ( struct Window *wind , struct 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"


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

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

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

	return;
}

void
makelabelvisible(struct Gadget *gad)
{
	extern int bgc, bpc;

	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(struct Gadget *gad)
{
	DPOS;

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

	/*
	 * FillGadget() löscht den Hintergrund eines Boolean-Gadgets
	 */
static void
FillGadget( struct Window *wind, struct 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(struct Window *wind, struct Gadget *gad, struct List *list, int top)
{
	struct List *lvlist = (list != NULL) ? list : (struct 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(struct Window * win)
{
	struct Requester *req = NULL;

	DPOS;

   if(!win) return NULL;

	req = (struct Requester *) MyAllocVec(sizeof(struct 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((struct Requester *) req, ((struct 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(struct Window *window)
{
	GT_BeginRefresh(window);
	GT_EndRefresh(window, TRUE);

	return;
}

void
MakePattern(struct Window *wind)
{
   struct 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(struct 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(struct Window *wind, struct Gadget **gads,
					 int *gadnum, int cnt, int SaveGad,
                struct Gadget *GadgetList)
{
	struct RastPort *RP = wind->RPort;
	struct Gadget *gad;
	register 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(struct Window *wnd)
{
	struct IntuiMessage *message;

	DPOS;

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

	return;
}

	/*
	 * OpenMainWindow() öffnet das Hauptffenster
	 */
void
OpenMainWindow(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(struct Window **wind, struct Gadget **windgadlist, struct 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(struct 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(struct 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.
	 */
struct Screen *
FindFrontPubScr(struct Screen *activescr)
{
	char	newnamebuffer[MAXPUBSCREENNAME + 1];
	UBYTE *test;
	struct 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)
{
	extern struct Screen *lastpubscreen;

	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;
	struct Process *p = (struct 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
	 */
void
PrintStatistics(void)
{
	char	help[BUFSIZE], *type = EntryAttr[LastID].ea_type;

	DPOS;

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

	if (countentries == 0) sprintf(help, "No %s entries read", type);
	else
		if (EntryAttr[LastID].ea_counted) sprintf(help, "%ld %s entries read", countentries,type);
		else
			sprintf(help, "%s entries read", type);

	PrintInfo(help, SPEAK, 0);

	RefreshListView();

	return;
}

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

	DPOS;

	Easy.es_StructSize = sizeof(struct 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;
}

