
/* MenuMgr_textmenu.c */

#include <stdio.h>
#include <sys/types.h>
#include <X10/Xlib.h>

#include "MenuMgr.h"

int		mm_Freeze = 0;

extern int		mm_debug;
extern int		mm_CanInvert;
extern FontFamily	mm_Fonts;
extern XAssocTable *	mm_AssocTable;
extern Cursor		mm_Cursor;
extern Defaults		mm_Defs;

#define max(a,b)	( ((a) > (b)) ? (a) : (b) ) 
#define min(a,b)	( ((a) < (b)) ? (a) : (b) ) 

#define DEBUG( n,s )	if(mm_debug && n>=mm_debug) printf s

/* ---------------------------------------------------------------------- */

int
mm_TextMenu( theMsg, theMenu, erase, item )

	int		theMsg;
	MenuPtr		theMenu;
	int		erase;		/* if msg is draw and erase true ... */
	int		item;		/* the new item (if any) */
{
static char *funcname = "mm_TextMenu";

	if( theMsg == msgDraw )
	{
		mm_DrawTextMenu( theMenu, erase );
	}
	else if( theMsg == msgChoose )
	{
		mm_ChooseTextMenu( theMenu, item );
	}
	else if( theMsg == msgCalcSize )
	{
		mm_CalcTextMenu( theMenu );
	}
	else
	{
		fprintf(stderr,"%s: message id %d not understood\n",
			funcname,theMsg );
		return -1;
	}

	return 0;
}

/* ---------------------------------------------------------------------- */

int
mm_CalcTextMenu( mp )

	MenuPtr		mp;
{
int	itemheight;
int	menuwidth = 0;
int	thiswidth, thisheight;
int	menuheight = 0;
int	i;
ItemPtr	ip;
TextDataPtr	tdp;
char	cs[2];
int	ax, ay;		/* absolute coords */
int	minwidth;	/* menu must be as wide as title */
WindowInfo	wi;
DefsPtr	d = &mm_Defs;

	if( !mp || !mp->menuBar )
		return -1;

	/* first, calc minimum width of any single item */
	XQueryWindow( mp->menuTitleWindow, &wi );
	minwidth = wi.width - 2*d->extMborder;

	/* now, calc maximum height of any single item */

	itemheight = mm_Fonts.fi[mm_Fonts.tallest]->height;

	mm_CountMItems( mp );
	itemheight += 2*d->intIborder;

	Get_Absolute_Coords( mp->menuBar->mbarMenuWindow,
		0,0,
		&ax,&ay	);

	ax -= d->extMborder;
	ay -= d->extMborder;

	if( !mp->menuWindow )
	{
		mp->menuWindow = XCreateWindow( RootWindow,
			ax+mp->menuLeftEdge,
			ay+mp->menuBar->mbarBottomEdge,
			20,40,	/* arbitrary */
			d->extMborder,d->fgpixmap,d->bgpixmap);
		XDefineCursor( mp->menuWindow, mm_Cursor );
	}
	if( !mp->menuShadow )
	{	/* arbitrary coords*/
		mp->menuShadow = XCreateWindow( RootWindow,
			ax+mp->menuLeftEdge,
			ay+mp->menuBar->mbarBottomEdge,
			20,40,	
			0,d->bgpixmap,d->fgpixmap);
		XDefineCursor( mp->menuShadow, mm_Cursor );
	}

	/* now go through the item list; find max width, height;
		and make any windows */

	for( 	i=0, menuheight = 0, ip = mp->menuItems;
		ip;
		ip=ip->itemNext, i++ )
	{
		tdp = (TextDataPtr) ip->itemData;

		if( ip->itemLabel[0] == '-' )
			thisheight = itemheight/2;
		else
			thisheight = itemheight;

		thiswidth = 0;
		thiswidth += d->intIborder;
		thiswidth += d->fontsize;	/* leave room for check */
		thiswidth += d->intIborder;
		thiswidth += max( XStringWidth(ip->itemLabel,
			mm_Fonts.fi[d->onstyle],0,0), 
			XStringWidth(ip->itemLabel,
			mm_Fonts.fi[d->offstyle],0,0) );
		thiswidth += d->intIborder;
		if( tdp->tdEquiv )
		{
			thiswidth += d->fontsize;
			sprintf(cs,"%c",tdp->tdEquiv);
			thiswidth += XStringWidth(cs,
				mm_Fonts.fi[mm_Fonts.widest],0,0);
			thiswidth += d->intIborder;
		}

		if( thiswidth > menuwidth )
			menuwidth = thiswidth;

		if( !ip->itemWindow )	/* make the window */
		{
			ip->itemWindow = 
			XCreateTransparency( mp->menuWindow,
				0,menuheight,thiswidth,thisheight );
			XSelectInput( ip->itemWindow, mm_ItemEvents );
			XMakeAssoc(mm_AssocTable,ip->itemWindow,(caddr_t)ip);
		}

		menuheight += thisheight;
	}

	mp->menuHeight = menuheight;
	mp->menuWidth = menuwidth;
	if( menuwidth < minwidth )
		mp->menuWidth = minwidth;

	if( !mp->menuBar )
		return 0;

	XConfigureWindow( mp->menuWindow,
		ax+mp->menuLeftEdge,
		ay+mp->menuBar->mbarBottomEdge,
		mp->menuWidth,mp->menuHeight );
	XConfigureWindow( mp->menuShadow,
		ax+mp->menuLeftEdge+d->xoff,
		ay+mp->menuBar->mbarBottomEdge+d->yoff,
		mp->menuWidth,mp->menuHeight );

	/* go through list again; correct the item windows */

	for( 	i=0, ip = mp->menuItems, menuheight = 0;
		ip;
		ip=ip->itemNext, i++ )
	{
		if( ip->itemLabel[0] != '-' )
		{
			XConfigureWindow( ip->itemWindow,
				0,menuheight,
				mp->menuWidth,itemheight );
			menuheight += itemheight;
		}
		else
		{
			XConfigureWindow( ip->itemWindow,
				0,menuheight,
				mp->menuWidth,itemheight/2 );
			menuheight += itemheight/2;
		}
	}

	return 0;
}

/* ---------------------------------------------------------------------- */

int
mm_DrawTextMenu( mp, erase )

	MenuPtr		mp;
	int		erase;
{
ItemPtr		ip;
WindowInfo	mwi, swi;
int		x,y;
DefsPtr d = &mm_Defs;

	if( erase )
	{
		XUnmapWindow( mp->menuShadow );
		XUnmapWindow( mp->menuWindow );
		if( !mm_Freeze )
			return 0;
		XQueryWindow( mp->menuWindow, &mwi );
		x = min( mwi.x, mwi.x+d->xoff );
		y = min( mwi.y, mwi.y+d->yoff );
		if( mp->menuSaved )
		{
			XPixmapPut( RootWindow,
			0,0,x,y,
			mp->menuWidth + abs(d->xoff) + 2*d->extMborder,
			mp->menuHeight + abs(d->xoff) + 2*d->extMborder,
			mp->menuSaved,
			GXcopy,AllPlanes );
			XFreePixmap( mp->menuSaved );			
		}
		return 0;
	}

	if( mm_Freeze )
	{
		XQueryWindow( mp->menuWindow, &mwi );
		x = min( mwi.x, mwi.x+d->xoff );
		y = min( mwi.y, mwi.y+d->yoff );

		mp->menuSaved = XPixmapSave( RootWindow, 
			x,y,
			mp->menuWidth + abs(d->xoff) + 2*d->extMborder,
			mp->menuHeight + abs(d->yoff) + 2*d->extMborder );
	}

	XMapWindow( mp->menuShadow );
	XMapWindow( mp->menuWindow );
	XMapSubwindows( mp->menuWindow );

	for(	ip = mp->menuItems;
		ip;
		ip=ip->itemNext	)
	{
		mm_DrawTextItemPtr( mp, ip, 0 );	/* not hilited */
	}
	return 0;
}

/* ---------------------------------------------------------------------- */

int
mm_DrawTextItem( mp, number, hilite )

	MenuPtr		mp;
	int		number;
	int		hilite;		/* if true, hilite it */
{
ItemPtr		ip, mm_GetItemHandle();

	ip = mm_GetItemHandle( mp, number );
	if( ip )
		return mm_DrawTextItemPtr( mp, ip, hilite );
	else
		return -1;
}

/* ---------------------------------------------------------------------- */

int
mm_DrawTextItemPtr( mp, ip, hilite )

	MenuPtr		mp;
	ItemPtr		ip;
	int		hilite;
{
int		x;
int		number;
char		cs[2];
static Pattern 	pattern;
static int 	made = 0;
Vertex 		vlist[2];
int		itemheight;
int		style;
ItemPtr		mm_GetItemHandle();
TextDataPtr	tdp;
int		fgcolor, bgcolor;
DefsPtr		d = &mm_Defs;

	if( mp==NULL || ip==NULL )
		return -1;

	tdp = (TextDataPtr) ip->itemData;
	itemheight = mm_Fonts.fi[mm_Fonts.tallest]->height + 2*d->intIborder;
	if( ip->itemLabel[0] == '-' )
		itemheight /= 2;

	if( hilite )
	{
		fgcolor = d->bgcolor;
		bgcolor = d->fgcolor;
	}
	else
	{
		fgcolor = d->fgcolor;
		bgcolor = d->bgcolor;
	}
	
	number = ip->itemNumber;

	if( ITEM_IS_ENABLED( mp, number ) )
		style = d->onstyle;
	else
		style = d->offstyle;

	XPixSet( ip->itemWindow, 0,0, mp->menuWidth, itemheight, bgcolor );

	if( ip->itemLabel[0] == '-' )	/* draw dashed line */
	{
	  	if( !made ) 
			{
				made=1;
				pattern = XMakePattern( 0x55, 8, 2 );
			}
		vlist[0].x = 0;
		vlist[0].y = itemheight/2;				
		vlist[0].flags = 0;
		vlist[1].x = mp->menuWidth;
		vlist[1].y = vlist[0].y;
		vlist[1].flags = VertexDrawLastPoint;
		XDrawPatterned( ip->itemWindow,
			vlist, 2, 1,1, fgcolor, bgcolor,
			pattern, GXcopy, AllPlanes );
		return 0;
	}

	x = 0;
	x += d->intIborder;

	if( tdp->tdMarked )
	{
		XPixmapPut( ip->itemWindow,0,0,x,d->intIborder,
			d->fontsize,d->fontsize,
			(hilite ? mm_Fonts.rv_check : mm_Fonts.check),
			GXcopy,AllPlanes );
	}
	x += d->fontsize;
	x += d->intIborder;
		
	XTextMask( ip->itemWindow,x,d->intIborder,
		ip->itemLabel,strlen(ip->itemLabel),
		mm_Fonts.fi[style]->id, fgcolor );
		
	if( tdp->tdEquiv )
	{
		x = mp->menuWidth;
		x -= d->intIborder;
		sprintf(cs,"%c",tdp->tdEquiv);
		x -= XStringWidth(cs,mm_Fonts.fi[style],0,0);
		x -= d->fontsize;	/* room for control icon */
		XPixmapPut( ip->itemWindow,0,0,x,d->intIborder,
			d->fontsize,d->fontsize,
			(hilite ? mm_Fonts.rv_kb : mm_Fonts.kb),
			GXcopy,AllPlanes );
		x += d->fontsize;
		XTextMask( ip->itemWindow,x,d->intIborder,
			cs,strlen(cs),
			mm_Fonts.fi[style]->id,fgcolor );
	}

	return 0;
}

/* ---------------------------------------------------------------------- */

int
mm_ChooseTextMenu( theMenu, item )

	MenuPtr		theMenu;
	int		item;
{

	if( theMenu==NULL || item < 0 )
		return -1;

	if( theMenu->menuLastItem )
	{
		if( mm_CanInvert )
			mm_InvertTextItem( theMenu, theMenu->menuLastItem );
		else
			mm_DrawTextItem( theMenu, theMenu->menuLastItem, 0 );
	}

	if( ITEM_IS_ENABLED( theMenu, item ) && item > 0 &&
	    theMenu->menuLastItem != item )
	{
		if( mm_CanInvert )
			mm_InvertTextItem( theMenu, item );
		else
			mm_DrawTextItem( theMenu, item, 1 );

		theMenu->menuLastItem = item;
	}
	else
		theMenu->menuLastItem = 0;

	return 0;
}

/* ---------------------------------------------------------------------- */

int
mm_InvertTextItem( theMenu, item )

	MenuPtr		theMenu;
	int		item;
{
ItemPtr		ip;
int		itemheight;
DefsPtr		d = &mm_Defs;

	ip = mm_GetItemHandle(theMenu, item );
	itemheight = mm_Fonts.fi[mm_Fonts.tallest]->height 
		+ 2*d->intIborder;
	if( ip->itemLabel[0] == '-' )
		itemheight /= 2;

	XPixFill( ip->itemWindow, 0,0, 
		theMenu->menuWidth, itemheight,
		BlackPixel, (Bitmap)0,
		GXinvert, 1 );
	return 0;
}
