/******************************************************************************

    MODUL
	win.c

    DESCRIPTION
	Everything for windows and GUI

    NOTES

    BUGS

    TODO

    EXAMPLES

    SEE ALSO

    INDEX

    HISTORY
	14. Nov 1992	ada created

******************************************************************************/

/**************************************
		Includes
**************************************/
#include "defs.h"


/**************************************
	    Globale Variable
**************************************/
Prototype void		  do_iconify	    (void);
Prototype void		  iconify	    (void);
Prototype void		  uniconify	    (void);
Prototype void		  do_newwindow	    (void);
Prototype void		  do_openwindow     (void);
Prototype struct Window * TOpenWindow	    (struct NewWindow *);
Prototype struct Window * opensharedwindow  (struct NewWindow *);
Prototype void		  closesharedwindow (struct Window *);
Prototype int		  getyn 	    (char *, char *, char *, ...);
Prototype void		  title 	    (char *);
Prototype void		  window_title	    (void);
Prototype void		  set_window_params (void);
Prototype void		  do_resize	    (void);
Prototype char		* geoskip	    (char *, int *, int *);
Prototype void		  prop_adj	    (void);
Prototype struct Gadget * add_prop	    (struct Window *);
Prototype void		  rest_prop	    (ED *);
Prototype ULONG 	  new_top	    (void);
Prototype void		  GeometryToNW	    (char *, struct NewWindow *);
Prototype void		  do_title	    (void);
Prototype void		  error 	    (char *, ...);
Prototype void		  warn		    (char *, ...);


/**************************************
      Interne Defines & Strukturen
**************************************/
#define IDCMPFLAGS   (IDCMP_CLOSEWINDOW |\
		      IDCMP_NEWSIZE |\
		      IDCMP_RAWKEY |\
		      IDCMP_MOUSEBUTTONS |\
		      IDCMP_ACTIVEWINDOW |\
		      IDCMP_MOUSEMOVE |\
		      IDCMP_MENUPICK |\
		      IDCMP_GADGETUP |\
		      IDCMP_GADGETDOWN)

#define WINDOWFLAGS  (WFLG_ACTIVATE |\
		      WFLG_SIZEGADGET |\
		      WFLG_DRAGBAR |\
		      WFLG_DEPTHGADGET |\
		      WFLG_CLOSEGADGET |\
		      WFLG_NOCAREREFRESH)

#define ICONIFYFLAGS (WFLG_DRAGBAR |\
		      WFLG_RMBTRAP |\
		      WFLG_DEPTHGADGET |\
		      WFLG_NOCAREREFRESH)

struct NewWindow Nw = {
   0, 1, 0  , 0  , 0, 0,  /*  width, height filled in by program */
   IDCMPFLAGS, WINDOWFLAGS,
   NULL, NULL, (ubyte *)"XDME V1.54 AD © 1988-92 by M. Dillon, All Rights Reserved",
   NULL, NULL,
   64, 32, (USHORT)-1, (USHORT)-1,
   WBENCHSCREEN
};

/* prop gadget stuff (TJM) */
#ifndef max
#define max(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef min
#define min(a,b) ((a)<(b)?(a):(b))
#endif

/* so we can malloc it all at once ... */
struct PropGadget PropTemp = {
  { NULL, -13, 0, 10, 0, GFLG_RELRIGHT|GFLG_RELHEIGHT,
    GACT_RIGHTBORDER|GACT_RELVERIFY|GACT_IMMEDIATE|GACT_FOLLOWMOUSE,
    GTYP_PROPGADGET
  },
};

/* end of Prop stuff */


/**************************************
	    Interne Variable
**************************************/
static short	 Oldtlen      = 999; /* Old Title Length */


/**************************************
	   Interne Prototypes
**************************************/


void do_iconify (void)
{
    text_sync ();

    if (!Comlinemode)
	iconify ();
} /* do_iconify */


/* New iconify() routine by fgk. */

void iconify (void)
{
    WIN 	   * newwin;
    ED		   * ep      = Ep;
    WIN 	   * win     = ep->Win;
    struct IntuiText itxt;		/* To find width of prop fonts */

    itxt.ITextFont = Ep->Win->WScreen->Font;	/* Init */
    itxt.NextText  = NULL;

    if (!ep->iconmode) {
	ep->Winx      = win->LeftEdge;
	ep->Winy      = win->TopEdge;
	ep->Winwidth  = win->Width;
	ep->Winheight = win->Height;

	if(Ep->Win->WScreen->Font != NULL)
	    Nw.Height = Ep->Win->WScreen->Font->ta_YSize + 3;	/* height */
	else
	    Nw.Height = GfxBase->DefaultFont->tf_YSize + 3;

	itxt.IText = ep->Name;

	/* pretending spaces are always 8 */
	Nw.Width  = 60 + IntuiTextLength(&itxt);          /* width */

	Nw.LeftEdge = ep->IWinx;
	Nw.TopEdge  = ep->IWiny;

	if (Nw.LeftEdge + Nw.Width > win->WScreen->Width)   /* keep in bounds */
	    Nw.LeftEdge = win->WScreen->Width - Nw.Width;

	if (Nw.TopEdge + Nw.Height > win->WScreen->Height)
	    Nw.TopEdge = win->WScreen->Height - Nw.Height;

	Nw.Title = ep->Wtitle;
	Nw.Flags = ICONIFYFLAGS;

	if (!ep->Modified) {     /* no CLOSE */
	    Nw.Flags |= WFLG_CLOSEGADGET;
	}

	Nw.DetailPen = ep->BGPen;
	Nw.BlockPen  = ep->FGPen;

#ifdef NOTDEF
	if (win->Flags & WFLG_WINDOWACTIVE)      /*  KTS */
	    Nw.Flags |= WFLG_ACTIVATE;
#endif

	sprintf (ep->Wtitle, "%s", ep->Name);

	if (newwin = opensharedwindow (&Nw)) {
	    closesharedwindow (win);

	    Nw.BlockPen  = (unsigned char)-1;
	    ep->iconmode = 1;
	    ep->Win	 = newwin;
	}

	Nw.Flags = WINDOWFLAGS;
    }
} /* iconify */


void uniconify (void)
{
    ED	* ep = Ep;
    WIN * win = ep->Win;
    WIN * newwin;
    RP	* rp;

    if (ep->iconmode) {
	ep->IWinx    = win->LeftEdge;
	ep->IWiny    = win->TopEdge;
	Nw.LeftEdge  = ep->Winx;
	Nw.TopEdge   = ep->Winy;
	Nw.Width     = ep->Winwidth;
	Nw.Height    = ep->Winheight;
	Nw.Title     = ep->Wtitle;
	Nw.DetailPen = ep->BGPen;
	Nw.BlockPen  = ep->FGPen;

	if (newwin = opensharedwindow (&Nw)) {
	    closesharedwindow (win);

	    win = ep->Win = newwin;
	    rp	= win->RPort;

	    if (ep->Font)
		SetFont (rp, ep->Font);

	    set_window_params ();
	    rest_prop (ep);

	    if (!text_sync ())
		text_redisplay ();

	    /* text_cursor (1); */
	    MShowTitle	 = 0;
	    ep->iconmode = FALSE;

	    menu_strip (win);
	    window_title ();
	}
    }
} /* uniconify */


void do_newwindow (void)
{
    WIN * win;

    if (Ep)
	text_sync ();

    Nw.Title = (ubyte *)"    OK    ";

    if (text_init (Ep, NULL, &Nw)) {
	if (win = opensharedwindow (&Nw)) {
	    menu_strip (win);

	    Ep->Win = win;
	    set_window_params ();
	    Ep->PropGad = add_prop (win);

	    text_load ();
	} else {
	    text_uninit ();
	} /* if opensharedwindow */
    } /* if text_init */
} /* do_newwindow */


/*
 *  openwindow with geometry specification.  Negative number specify
 *  relative-right / relative-left (leftedge & topedge), or relative-width /
 *  relative height (width & height).
 *
 *	<leftedge><topedge><width><height>
 *
 *  Example:	+10+10-20-20	Open window centered on screen 10 pixels
 *				from the border on all sides.
 */

void do_openwindow (void)
{
    WIN *win;

    if (Ep)
	text_sync ();
    Nw.Title = (ubyte *)"    OK    ";

    if (text_init (Ep, NULL, &Nw)) {
	GeometryToNW (av[1], &Nw);

	if (win = opensharedwindow (&Nw)) {
	    menu_strip (win);

	    Ep->Win = win;
	    set_window_params ();
	    Ep->PropGad = add_prop (win);

	    text_load ();
	} else {
	    text_uninit ();
	} /* if opensharedwindow */
    } /* if text_init */
} /* do_openwindow */


WIN * TOpenWindow (struct NewWindow * nw)
{
    WIN * win;
    struct Screen * PubScreen = NULL;

    if (PubScreenName) {
	PubScreen = LockPubScreen (PubScreenName);

	nw->Screen = PubScreen;     /* Try your luck on a pubscreen */
	nw->Type   = PUBLICSCREEN;
    } else {
	nw->Screen = NULL;
	nw->Type   = WBENCHSCREEN;
    }

    while ((win = OpenWindow (nw)) == NULL) {
	if (nw->Width < 50 || nw->Height < 50)
	    break;

	nw->Width -= 10;
	nw->Height-= 10;
    } /* while OpenWindow */

    if (PubScreenName)
	UnlockPubScreen (NULL, PubScreen);

    return (win);
} /* TOpenWindow */


WIN * opensharedwindow (struct NewWindow *nw)
{
    WIN * win;

    if (Sharedport)
	nw->IDCMPFlags = 0L;
    else
	nw->IDCMPFlags = IDCMPFLAGS;

    win = TOpenWindow (nw);

    if (win) {
	long xend = win->Width - win->BorderRight - 1;
	long yend = win->Height- win->BorderBottom - 1;

	if (Sharedport) {
	    win->UserPort = Sharedport;
	    ModifyIDCMP (win, IDCMPFLAGS);
	} else {
	    Sharedport = win->UserPort;
	}

	if (xend > win->BorderLeft && yend > win->BorderTop) {
	    SetAPen (win->RPort, nw->DetailPen);
	    RectFill (win->RPort, win->BorderLeft, win->BorderTop, xend, yend);
	    SetAPen (win->RPort, nw->BlockPen);
	}
    }

    return (win);
} /* opensharedwindow */


/* the following function straight from RKM by TJM */
static void StripIntuiMessages(struct MsgPort *,struct Window *);

static void StripIntuiMessages (struct MsgPort *mp, struct Window *win)
{
    IMESS *msg, *succ;

    msg = (IMESS *)mp->mp_MsgList.lh_Head;

    while (succ = (IMESS *)msg->ExecMessage.mn_Node.ln_Succ) {
	if (msg->IDCMPWindow == win) {
	    Remove ((struct Node *)msg);
	    ReplyMsg ((struct Message *)msg);
	}

	msg = succ;
    }
} /* StripIntuiMessages */

/* modifed TJM to close win's immediately using CloseWindowSafely from RKM */
void closesharedwindow (WIN * win)
{
    if (win) {
	SetWindowTitles (win, "", (char *)-1);
	ClearMenuStrip (win);

	Forbid ();

	StripIntuiMessages (win->UserPort,win);

	win->UserPort = NULL;
	ModifyIDCMP (win,0);

	Permit ();

	CloseWindow (win);
    }
}


int getyn (char * title, char * text, char * gads, ...)
{
    va_list va;
    int     result;

    va_start (va, gads);

    if (IntuitionBase->LibNode.lib_Version >= 36) {
	static struct EasyStruct es = {
	    sizeof (struct EasyStruct),
	    0L, 0, 0, 0
	};

	es.es_Title	   = title;
	es.es_TextFormat   = text;
	es.es_GadgetFormat = gads;

	result = EasyRequestArgs (Ep->Win, &es, NULL, va);
    } else {
	ITEXT *body, *pos, *neg;

	body = (ITEXT *)AllocMem (sizeof(ITEXT), MEMF_CLEAR);
	pos  = (ITEXT *)AllocMem (sizeof(ITEXT), MEMF_CLEAR);
	neg  = (ITEXT *)AllocMem (sizeof(ITEXT), MEMF_CLEAR);

	body->BackPen = pos->BackPen = neg->BackPen = 1;
	body->DrawMode= pos->DrawMode= neg->DrawMode= AUTODRAWMODE;

	vsprintf (tmp_buffer, text, va);

	body->LeftEdge = 10;
	body->TopEdge  = 12;
	body->IText    = (ubyte *)tmp_buffer;
	pos->LeftEdge  = AUTOLEFTEDGE;
	pos->TopEdge   = AUTOTOPEDGE;
	pos->IText     = (ubyte *)"Ok";
	neg->LeftEdge  = AUTOLEFTEDGE;
	neg->TopEdge   = AUTOTOPEDGE;
	neg->IText     = (ubyte *)"Cancel";

	result = AutoRequest (Ep->Win,body,pos,neg,0,0,320,58);

	FreeMem (body, sizeof(ITEXT));
	FreeMem (pos , sizeof(ITEXT));
	FreeMem (neg , sizeof(ITEXT));
    }

    va_end (va);

    return (result);
} /* getyn */


void title (char * buf)
{
    SetWindowTitles (Ep->Win, buf, (char *)-1);
    Oldtlen = 999;
    MShowTitle = 3;
}


void window_title (void)
{
    if (memoryfail) {
	title(" -- NO MEMORY -- ");
	memoryfail = 0;
	text_redisplay ();
    }

    if (MForceTitle) {
	MShowTitle = 0;
	MForceTitle = 0;
    }

    if (MShowTitle) {
	--MShowTitle;
	return;
    }

    {
	int    len;
	int    maxlen;
	FONT * oldfont;
	ED   * ep    = Ep;
	WIN  * win   = ep->Win;
	RP   * rp    = win->RPort;
	ubyte  c;

	len = text_colno ();
	if (!(c = Current[len]) )
	    c = ' ';

	sprintf (ep->Wtitle, "%3ld/%-3ld %3ld %02x %c %s  ",
		text_lineno (),
		text_lines (),
		len+1,
		c,
		(ep->Modified ? '*' : ' '),
		text_name ()
	);

	if (!text_imode ())
	    strcat (ep->Wtitle, "Ovr ");

	len = strlen (ep->Wtitle);
	if (len < Columns && Columns < 128) {
	    setmem (ep->Wtitle+len, Columns - len + 1, ' ');
	    ep->Wtitle[Columns + 1] = 0;
	}

	/*
	 *  Update title
	 */

	oldfont = win->RPort->Font;
	SetFont (rp, win->WScreen->RastPort.Font);

	win->Title = ep->Wtitle;

	SetAPen (rp, ep->FGPen);
	SetBPen (rp, ep->TPen);
	SetDrMd (rp, JAM2);
	Move (rp, 30, rp->Font->tf_Baseline+1);

	maxlen = (win->Width-96)/rp->Font->tf_XSize;
	if (maxlen < 0)
	    maxlen = 0;
	if (len > maxlen)
	    len = Oldtlen = maxlen;
	if (Oldtlen > maxlen)
	    Oldtlen = maxlen;

	Text (rp, ep->Wtitle, len);      /* No flash */

	while (Oldtlen - len >= sizeof (Space)) {
	    Text (rp, Space, sizeof (Space));
	    Oldtlen -= sizeof (Space);
	}

	if (Oldtlen - len > 0)
	    Text (rp, Space, Oldtlen - len);

	Oldtlen = len;			/*  Oldtlen might have been <	*/

	SetAPen (rp, ep->FGPen);
	SetBPen (rp, ep->BGPen);
	SetFont (rp, oldfont);
    }
} /* window_title */


void set_window_params (void)
{
    ED	* ep = Ep;
    WIN * win = ep->Win;
    RP	* rp = win->RPort;
    short t;
    short x;

    /* Set Character-Size */
    Xsize = rp->Font->tf_XSize;
    Ysize = rp->Font->tf_YSize;

    /* Set Borders */
    Xbase = win->BorderLeft;
    Ybase = win->BorderTop;

    /* Find Width/Height */
    Xpixs   = win->Width - win->BorderRight - Xbase;
    Ypixs   = win->Height- win->BorderBottom- Ybase;

    /* Find Width/Height in Characters */
    Columns = Xpixs / Xsize;
    Rows    = Ypixs / Ysize;

    /* Now Calculate Xpixs/Ypixs */
    Xpixs = Xbase + Columns * Xsize - 1;
    Ypixs = Ybase + Rows    * Ysize - 1;

    /* Set Base for Text() */
    XTbase  =  Xbase;
    YTbase  =  Ybase + rp->Font->tf_Baseline;

    /* Set Pens */
    SetAPen(rp, ep->FGPen);
    SetBPen(rp, ep->BGPen);

    /* Initialize Arrays of X/Y-Coords for faster rendering */
    for (t=0, x=0; t<MAXLINELEN; t++, x += Xsize)
	ColumnPos[t] = x;

    for (t=0, x=0; t<MAXROWS; t++, x += Ysize)
	RowPos[t] = x;
}


/* resize cols rows */

void do_resize (void)
{
    WIN * win	 = Ep->Win;
    int   cols	 = atoi (av[1]);
    int   rows	 = atoi (av[2]);
    short width  = (cols*win->RPort->Font->tf_XSize) + win->BorderLeft +
		   win->BorderRight;
    short height = (rows*win->RPort->Font->tf_YSize) + win->BorderTop +
		   win->BorderBottom;

    if (cols < 2 || rows < 1) {
	error ("resize:\nCannot make window this small.\n"
	       "Window must have at least 2 columns and 1 row !");
    } else if (width > win->WScreen->Width - win->LeftEdge ||
	    height > win->WScreen->Height - win->TopEdge) {
	error ("resize:\nwindow too big (move it to\n"
	       "upper left corner and retry)");
    } else {
	SizeWindow (win, width - win->Width, height - win->Height);
	Delay (5);    /* wait 0.1 seconds for OS to resize */
    }
} /* do_resize */


/* Convert geometry to nw params. */

char * geoskip (char * ptr, int * pval, int * psgn)
{
    ptr = skip_whitespace (ptr);

    if (*ptr == '-')
	*psgn = -1;
    else
	*psgn = 1;

    if (*ptr == '-' || *ptr == '+')
	ptr ++;

    *pval = strtol (ptr, &ptr, 0);

    return (ptr);
}


/* Convert GEO-String to NewWindow-structure */

void GeometryToNW (char * geo, struct NewWindow *nw)
{
    int 	  n;
    int 	  sign;
    struct Screen scr;

    GetScreenData (&scr, sizeof (scr), WBENCHSCREEN, NULL);

    if (*geo) {
	geo = geoskip (geo, &n, &sign);
	if (sign > 0)
	    nw->LeftEdge = n;
	else
	    nw->LeftEdge = scr.Width - n;
    }

    if (*geo) {
	geo = geoskip (geo, &n, &sign);
	if (sign > 0)
	    nw->TopEdge = n;
	else
	    nw->TopEdge = scr.Height - n;
    }

    if (*geo) {
	geo = geoskip (geo, &n, &sign);
	if (sign > 0)
	    nw->Width = n;
	else
	    nw->Width = scr.Width - nw->LeftEdge - n;
    }

    if (*geo) {
	geo = geoskip (geo, &n, &sign);
	if (sign > 0)
	    nw->Height = n;
	else
	    nw->Height = scr.Height - nw->TopEdge - n;
    }
} /* GeometryToNW */


/* prop gadget stuff (TJM) */

void rest_prop (ED * ep)
{
    if (ep->PropGad) {
	AddGadget (ep->Win,ep->PropGad,0);
	RefreshGList (ep->PropGad,ep->Win,NULL,1);
    }
} /* rest_prop */


struct Gadget * add_prop (struct Window * win)
{
    struct PropGadget *pg;

    if(!(pg = (struct PropGadget *)AllocMem(sizeof(struct PropGadget), 0)))
	return NULL;

    memcpy(pg,&PropTemp,sizeof(PropTemp));

    if (IntuitionBase->LibNode.lib_Version >= 36) {
	/* PROPNEWLOOK is 2.0-dependent. PROPBORDERLESS looks better :-) */
	pg->p.Flags = PROPNEWLOOK;
    }

    pg->g.TopEdge = win->BorderTop + 1;
    pg->g.Height = -(win->BorderTop + 12);
    pg->p.Flags |= AUTOKNOB|FREEVERT;
    pg->p.HorizPot =
	pg->p.VertPot =
	pg->p.HorizBody =
	pg->p.VertBody = (unsigned short)-1;
    pg->g.SpecialInfo = (APTR)&pg->p;
    pg->g.GadgetRender = &pg->i;

    AddGadget(win,&pg->g,0);
    RefreshGList(&pg->g,win,NULL,1);
    noadj = 0;	    /* allow scroller refreshing */

    return (&pg->g);
} /* add_prop */


void prop_adj (void)
{
    ULONG hidden = max(Ep->Lines - Rows, 0);
    ULONG VertBody, VertPot;
    ULONG topLine = min(Ep->Topline,hidden);
    ULONG Overlap = (Rows * (100 - PageJump)) / 100;

    if (!Ep->PropGad || noadj || Ep->iconmode)       /* block adjustment when already set by prop gad */
	return;

    if(hidden > 0) {
	VertBody = ((Rows - Overlap) * MAXBODY) / (Ep->Lines - Overlap);
	VertPot = (topLine * MAXPOT) / hidden;
    }
    else {
	VertBody = MAXBODY;
	VertPot = 0;
    }

    NewModifyProp(Ep->PropGad, Ep->Win, NULL,
	((struct PropInfo *)Ep->PropGad->SpecialInfo)->Flags,
	MAXPOT, VertPot,
	MAXBODY, VertBody,
	1
    );
} /* prop_adj */


ULONG new_top (void)
{
    ULONG hidden = max(Ep->Lines - Rows, 0);

    return (hidden * ((struct PropInfo *)Ep->PropGad->SpecialInfo)->VertPot +
	MAXPOT/2) / MAXPOT;
} /* new_top */


void do_title (void)
{
    static char buffer[256];

    strncpy ((char *)buffer, (char *)av[1], 255);
    buffer[255] = 0;

    title ((char *)buffer);
} /* do_title */


void error (char * fmt, ...)
{
    va_list va;

    va_start (va, fmt);

    Abortcommand = 1;

    if (IntuitionBase->LibNode.lib_Version >= 36) {
	static struct EasyStruct es = {
	    sizeof (struct EasyStruct),
	    NULL,
	    "XDME Error",
	    NULL,
	    "Ok"
	};

	es.es_TextFormat = fmt;

	EasyRequestArgs (Ep->Win, &es, NULL, va);
    } else {
	char * ptr;

	vsprintf (tmp_buffer, fmt, va);

	ptr = tmp_buffer;

	while (*ptr) {
	    if (*ptr == '\n') *ptr = ' ';

	    ptr ++;
	}

	title (tmp_buffer);
    }

    va_end (va);
} /* error */


void warn (char * fmt, ...)
{
    va_list va;
    char  * ptr;

    va_start (va, fmt);

    vsprintf (tmp_buffer, fmt, va);

    title (tmp_buffer);

    va_end (va);
} /* warn */


/******************************************************************************
*****  ENDE win.c
******************************************************************************/
