/* 
 * Motif Tools Library, Version 2.0
 * $Id: LayoutString.c,v 2.9 1994/07/04 03:03:50 david Exp $
 * 
 * Written by David Flanagan.
 * Copyright (c) 1992, 1993, 1994 by Dovetail Systems.
 * All Rights Reserved.  See the file COPYRIGHT for details.
 * This is not free software.  See the file SHAREWARE for details.
 * There is no warranty for this software.  See NO_WARRANTY for details.
 */

#include <Xmt/Xmt.h>
#include <Xmt/LayoutGP.h>
#include <Xmt/Converters.h>

#define offset(field) XtOffsetOf(XmtLayoutStringRec, layout_string.field)
static XtResource resources[] = {
{XmtNlabel, XtCLabel, XtRString,
     sizeof(String), offset(label),
     XtRString, (XtPointer) NULL},
{XmtNlabelString, XmCLabelString, XmRXmString,
     sizeof(XmString), offset(label_string),
     XmRXmString, (XtPointer)NULL},
{XmtNforeground, XtCForeground, XtRPixel,
     sizeof(Pixel), offset(foreground),
     XtRImmediate, (XtPointer) -1},
{XmtNbackground, XtCBackground, XtRPixel,
     sizeof(Pixel), offset(background),
     XtRImmediate, (XtPointer) -1}
};
#undef offset

#if NeedFunctionPrototypes
static void Initialize(Widget, Widget, ArgList, Cardinal *);
static void Destroy(Widget);
static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
static void Redisplay(Widget, XEvent *, Region);
static XtGeometryResult QueryGeometry(Widget, XtWidgetGeometry *,
                                      XtWidgetGeometry *);
static void ChangeFont(Widget);
#else
static void Initialize();
static void Destroy();
static Boolean SetValues();
static void Redisplay();
static XtGeometryResult QueryGeometry();
static void ChangeFont();
#endif

#define superclass (&xmtLayoutGadgetClassRec)

externaldef(xmtlayoutstringclasrec)
XmtLayoutStringClassRec xmtLayoutStringClassRec = {
{   /* rect_class fields  */
    /* superclass	  */	(WidgetClass)superclass,
    /* class_name	  */	"XmtLayoutString",
    /* widget_size	  */	sizeof(XmtLayoutStringRec),
    /* class_initialize   */    NULL,
    /* class_part_initialize*/	NULL,
    /* class_inited       */	FALSE,
    /* initialize	  */	Initialize,
    /* initialize_hook    */	NULL,		
    /* rect1		  */	NULL,
    /* rect2		  */	NULL,
    /* rect3	  	  */	0,
    /* resources	  */	resources,
    /* num_resources	  */	XtNumber(resources),
    /* xrm_class	  */	NULLQUARK,
    /* rect4		  */	FALSE,
    /* rect5		  */	FALSE,
    /* rect6		  */ 	FALSE,
    /* rect7		  */	FALSE,
    /* destroy		  */	Destroy,
    /* resize		  */	NULL,
    /* expose		  */	Redisplay,
    /* set_values	  */	SetValues,
    /* set_values_hook    */	NULL,			
    /* set_values_almost  */	XtInheritSetValuesAlmost,  
    /* get_values_hook    */	NULL,			
    /* rect9		  */	NULL,
    /* version		  */	XtVersion,
    /* callback_offsets   */    NULL,
    /* rect10	          */    NULL,
    /* query_geometry	  */	QueryGeometry,
    /* rect11		  */	NULL,
    /* extension	    */  NULL
  },
  { /* XmtLayoutGadget field */
    /* change_font        */    ChangeFont,
  },
  { /* XmtLayoutString fields */
    /* extension          */	NULL
  }
};

externaldef(xmtlayoutstringgadgetclass)
WidgetClass xmtLayoutStringGadgetClass = (WidgetClass)&xmtLayoutStringClassRec;

#define MARGINWIDTH 2
#define MARGINHEIGHT 2


#if NeedFunctionPrototypes
static void GetGC(XmtLayoutWidget lw, XmtLayoutStringGadget ls)
#else
static void GetGC(lw, ls)
XmtLayoutWidget lw;
XmtLayoutStringGadget ls;
#endif
{
    XGCValues gcv;

    if ((ls->layout_string.foreground == -1)  &&
	(ls->layout_string.background == -1)) {
	ls->layout_string.gc = None;
	return;
    }
    
    if (ls->layout_string.foreground != -1)
	gcv.foreground = ls->layout_string.foreground;
    else
	gcv.foreground = lw->manager.foreground;
    
    if (ls->layout_string.background != -1)
	gcv.background = ls->layout_string.background;
    else
	gcv.background = lw->core.background_pixel;
    
    /* we need to specify some font so XmDrawString() doesn't barf */
    gcv.font = lw->layout.font->fid;
    
    ls->layout_string.gc = XtGetGC((Widget)ls,
				  GCForeground | GCBackground | GCFont,
				  &gcv);
}

#if NeedFunctionPrototypes
static void MeasureString(XmtLayoutWidget lw, XmtLayoutStringGadget ls)
#else
static void MeasureString(lw, ls)
XmtLayoutWidget lw;
XmtLayoutStringGadget ls;
#endif
{
    if (ls->layout_string.label_string)
	XmStringExtent(lw->layout.font_list, ls->layout_string.label_string,
		       &ls->layout_string.width, &ls->layout_string.height);
    else 
	ls->layout_string.width = ls->layout_string.height = 0;

    ls->layout_string.width += 2*MARGINWIDTH;
    ls->layout_string.height += 2*MARGINHEIGHT;
}    

#if NeedFunctionPrototypes
static void ChangeFont(Widget w)
#else
static void ChangeFont(w)
Widget w;
#endif
{
    XmtLayoutWidget lw = (XmtLayoutWidget)XtParent(w);
    XmtLayoutStringGadget ls = (XmtLayoutStringGadget)w;

    MeasureString(lw, ls);
}

/* an empty string value unique to us. */
static String empty_string = "";

/* ARGSUSED */
#if NeedFunctionPrototypes
static void Initialize(Widget request, Widget init,
		       ArgList arglist, Cardinal *num_args)
#else
static void Initialize(request, init, arglist, num_args)
Widget request;
Widget init;
ArgList arglist;
Cardinal *num_args;
#endif
{
    XmtLayoutStringGadget ls = (XmtLayoutStringGadget) init;
    XmtLayoutWidget lw = (XmtLayoutWidget) XtParent(init);

    Constraint(ls, type) = XmtLayoutString;

    /* copy the XmString, if specified */
    if (ls->layout_string.label_string)
	ls->layout_string.label_string =
	    XmStringCopy(ls->layout_string.label_string);
    else if (ls->layout_string.label) {
	/* we don't copy the string; just convert it to an XmString */
	/* and then set it to "" because we don't own it. */
	ls->layout_string.label_string =
	    XmtCreateXmString(ls->layout_string.label);
	ls->layout_string.label = empty_string;
    }

    MeasureString(lw, ls);
    GetGC(lw, ls);
}

#if NeedFunctionPrototypes
static void Destroy(Widget w)
#else
static void Destroy(w)
Widget w;
#endif
{
    XmtLayoutStringGadget ls = (XmtLayoutStringGadget) w;

    if (ls->layout_string.label_string)
	XmStringFree(ls->layout_string.label_string);

    if (ls->layout_string.gc)
	XtReleaseGC(w, ls->layout_string.gc);
}

/* ARGSUSED */
#if NeedFunctionPrototypes
static Boolean SetValues(Widget current, Widget request, Widget set,
			 ArgList arglist, Cardinal *num_args)
#else
static Boolean SetValues(current, request, set, arglist, num_args)
Widget current;
Widget request;
Widget set;
ArgList arglist;
Cardinal *num_args;
#endif
{
    XmtLayoutStringGadget cs = (XmtLayoutStringGadget) current;
    XmtLayoutStringGadget ss = (XmtLayoutStringGadget) set;
    XmtLayoutWidget lw = (XmtLayoutWidget) XtParent(set);
    Boolean redisplay = False;
    Boolean relayout = False;

    if (ss->layout_string.label_string  != cs->layout_string.label_string) {
	if (cs->layout_string.label_string)
	    XmStringFree(cs->layout_string.label_string);
	ss->layout_string.label_string =
	    XmStringCopy(ss->layout_string.label_string);
	MeasureString(lw, ss);
	relayout = True;
    }
    else if (ss->layout_string.label != empty_string) {
	if (cs->layout_string.label_string)
	    XmStringFree(cs->layout_string.label_string);
	ss->layout_string.label_string =
	    XmtCreateXmString(ss->layout_string.label);
	MeasureString(lw, ss);
	relayout = True;
    }

    if ((ss->layout_string.foreground != cs->layout_string.foreground) ||
	(ss->layout_string.background != cs->layout_string.background)) {
	if (ss->layout_string.gc) XtReleaseGC(set, ss->layout_string.gc);
	GetGC(lw, ss);
	redisplay = True;
    }

    if (relayout) 
	_XmtLayoutChildren(lw, True);

    return redisplay | relayout;
}

/* ARGSUSED */
#if NeedFunctionPrototypes
static XtGeometryResult QueryGeometry(Widget w,
				      XtWidgetGeometry *request,
				      XtWidgetGeometry *reply)
#else
static XtGeometryResult QueryGeometry(w, request, reply)
Widget w;
XtWidgetGeometry *request;
XtWidgetGeometry *reply;
#endif
{
    XmtLayoutStringGadget ls = (XmtLayoutStringGadget) w;

    reply->request_mode = CWWidth | CWHeight;
    reply->width = ls->layout_string.width;
    reply->height = ls->layout_string.height;
    return XtGeometryYes;
}


/* ARGSUSED */
#if NeedFunctionPrototypes
static void Redisplay(Widget w, XEvent *event, Region region)
#else
static void Redisplay(w, event, region)
Widget w;
XEvent *event;
Region region;
#endif
{
    XmtLayoutStringGadget ls = (XmtLayoutStringGadget) w;
    XmtLayoutWidget lw = (XmtLayoutWidget) XtParent(w);

    if (lw->core.window == None) return;
    
    XmStringDraw(lw->core.screen->display, lw->core.window,
		 lw->layout.font_list, ls->layout_string.label_string,
		 (ls->layout_string.gc?ls->layout_string.gc:lw->layout.gc),
		 ls->rectangle.x + MARGINWIDTH,
		 ls->rectangle.y + MARGINHEIGHT,
		 ls->rectangle.width - 2*MARGINWIDTH,
		 XmALIGNMENT_BEGINNING, XmSTRING_DIRECTION_L_TO_R, NULL);
}

#if NeedFunctionPrototypes
Widget XmtCreateLayoutString(Widget parent, String name,
			     ArgList arglist, Cardinal num_args)
#else
Widget XmtCreateLayoutString(parent, name, arglist, num_args)
Widget parent;
String name;
ArgList arglist;
Cardinal num_args;
#endif
{
    return XtCreateWidget(name, xmtLayoutStringGadgetClass, parent,
			  arglist, num_args);
}
