/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include <stdio.h>
#include <math.h>

#ifndef M_PI
#define M_PI    3.14159265358979323846
#endif

#define  RADIANS(x)  (M_PI * (x) / 180.0)
#define  ROUND(X)  (((X) >= 0) ? (int)((X)+0.5) : (int)((X)-0.5))


#include      <X11/Intrinsic.h>
#include      <X11/IntrinsicP.h>
#include      <X11/StringDefs.h>
#include      <X11/CoreP.h>
#include    <X11/CompositeP.h>
#include      <X11/ConstrainP.h>
#include        <Xm/XmP.h>
#include        <Xm/DrawingAP.h>
#include      "Tab.h"
#include      "TabP.h"

#ifndef MAX
#define   MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#define   MIN(a,b) ((a) < (b) ? (a) : (b))
#endif

static void             Initialize();
static void             Resize();
static void             Destroy();
static void             ReDisplay();
static void             Click();
static void             Drag();
static void             Release();
static Boolean          SetValues();
static XtGeometryResult GeometryManager();
static void             ChangeManaged();
static void             new_layout(TabWidget,Boolean);
static void             ConstraintInitialize();
static void             ConstraintDestroy();
static Boolean          ConstraintSetValues();


#define DEBUG(a) printf("%s\n",a);

static XtResource resources[] = {
	{XmNvalueChangedCallback,XmCValueChangedCallback,XtRCallback,sizeof(XtPointer),
	XtOffset(TabWidget,tab.cb), XtRCallback, NULL },
	{XmNopenCallback,XmCValueChangedCallback,XtRCallback,sizeof(XtPointer),
	XtOffset(TabWidget,tab.open_cb), XtRCallback, NULL },

	{XmNcloseCallback,XmCValueChangedCallback,XtRCallback,sizeof(XtPointer),
	XtOffset(TabWidget,tab.close_cb), XtRCallback, NULL },

	{XmNfontList,XmCFontList,XmRFontList,sizeof(XmRFontList),
	XtOffset(TabWidget,tab.font),XmRString,(XtPointer)"fixed" },

	{ "Back", "back", XmRPixel,sizeof(Pixel),
	XtOffset(TabWidget,tab.back),XmRString,"#bcbcbcbcbcbc"},

	{ "Blue", "blue", XmRPixel,sizeof(Pixel),
	XtOffset(TabWidget,tab.blue),XmRString,"blue"},

	{ "drawer", "Drawer", XmRBoolean,sizeof(Boolean),
	XtOffset(TabWidget,tab.drawer),XmRString,"false"},
};


static XtActionsRec actions[] = {
	{"Click",Click},
	{"Drag",Drag},
	{"Release",Release}
};


static char translations[] =
"<Btn1Down>:  Click()\n\
<Btn1Motion>: Drag()\n\
<Btn1Up>:     Release()";

#define USE_MANAGER

TabClassRec tabClassRec = {
	{
	/* core_class fields  */
	(WidgetClass) &xmDrawingAreaClassRec,/* superclass         */
	"Tab",                           /* class_name         */
	sizeof(TabRec),                /* widget_size        */
	NULL,                             /* class_init         */
	NULL,                             /* class_part_init    */
	FALSE,                            /* class_inited       */
	Initialize,                       /* initialize         */
	NULL,                             /* initialize_hook    */
	XtInheritRealize,                 /* realize            */
	actions,                             /* actions            */
	XtNumber(actions),                                /* num_actions        */
	resources,                        /* resources          */
	XtNumber(resources),              /* num_resources      */
	NULLQUARK,                        /* xrm_class          */
	TRUE,                             /* compress_motion    */
	XtExposeCompressMaximal,          /* compress_exposure  */
	TRUE,                             /* compress_enterleave*/
	TRUE,                             /* visible_interest   */
	Destroy,                          /* destroy            */
	Resize,                           /* resize             */
	ReDisplay,                        /* expose             */
	SetValues,                        /* set_values         */
	NULL,                             /* set_values_hook    */
	XtInheritSetValuesAlmost,         /* set_values_almost  */
	NULL,                             /* get_values_hook    */
	NULL,                             /* accept_focus       */
	XtVersion,                        /* version            */
	NULL,                             /* callback_private   */
	translations,            /* tm_table           */
	NULL,                             /* query_geometry     */
	XtInheritDisplayAccelerator,      /* display_accelerator*/
	NULL,                             /* extension          */
	},
	{
	/* composite_class fields */
	GeometryManager,                 /* geometry_manager    */
	ChangeManaged,                   /* change_managed      */
	XtInheritInsertChild,            /* insert_child        */
	XtInheritDeleteChild,            /* delete_child        */
	NULL ,                           /* extension           */
	},
	{ 
	/* constraint_class fields */
	NULL,                             /* subresources        */
	0,                                /* subresource_count   */
	sizeof(TabConstraintsRec),        /* constraint_size     */
	ConstraintInitialize,             /* initialize          */
	ConstraintDestroy,                /* destroy             */
	ConstraintSetValues,              /* set_values          */
	NULL,                             /* extension           */
	},
	{
	XtInheritTranslations,   /* default translations */
	NULL,                    /* syn_resources          */
	0,               /* num_syn_resources      */
	NULL,                        /* syn_cont_resources     */
	0,                           /* num_syn_cont_resources */
	XmInheritParentProcess,  /* parent_process */
	NULL,                        /* extension              */

	},
	{
	NULL,
	},
	{
	/* Tab class fields */
	0,                               /* ignore              */
	},
};

static void make_visible(TabWidget tw,Widget w);

WidgetClass tabWidgetClass = (WidgetClass) &tabClassRec;

static void Initialize(TabWidget request, TabWidget new)
{

	XGCValues       values;
    XtGCMask        valueMask = 0;

	XFontStruct     *fs = (XFontStruct *) NULL;


	/*
   * Make sure the widget's width and height are 
   * greater than zero.
   */
	if (request->core.width <= 0)
		new->core.width = 5;
	if (request->core.height <= 0)
		new->core.height = 5;

	_XmFontListGetDefaultFont(new->tab.font,&fs);
	if(fs != NULL)
	{
		valueMask    |= GCFont;
		values.font  = fs->fid;
	}

	


	new->tab.gc     = XtGetGC((Widget)new,valueMask,&values);
	new->tab.current = 0;

	new->tab.hmargin = 8;
	new->tab.vmargin = 3;

	new->tab.top    = 2;
	new->tab.bottom = 2;
	new->tab.delta  = new->tab.hmargin;
	new->tab.drag   = False;

}

static char* name_of(Widget w)
{
	if(XmIsScrolledWindow(w))
	{
		static char name[90];
		strcpy(name,XtName(w));
		name[strlen(name)-2] = 0;
		return name;
	}
	else
		return XtName(w);	
		
}

static void ConstraintInitialize(Widget request, Widget new)
{
	TAB_CONSTRAINT(new)->tab.name = XmStringCreateSimple(name_of(new));
}

static void ConstraintDestroy(Widget w)
{
	XmStringFree(TAB_CONSTRAINT(w)->tab.name);
}

static Boolean ConstraintSetValues(Widget current, Widget request, Widget new)
{
	return False;
}

static void Destroy(TabWidget tw)
{


	XtReleaseGC((Widget)tw,tw->tab.gc);
}

static void Resize(TabWidget w)
{
	XmDrawingAreaCallbackStruct cb;
	new_layout(w,False);
	cb.reason = XmCR_RESIZE;
	cb.event = NULL;
	cb.window = XtWindow (w);
	XtCallCallbackList((Widget)w,w->drawing_area.resize_callback, &cb);
	make_visible(w,w->tab.current);
	if(XtIsRealized((Widget)w))
		XClearArea(XtDisplay(w),XtWindow(w),0,0,0,0,True);

	/* w->tab.wait = False; */
}

static Boolean SetValues(TabWidget current, TabWidget request, TabWidget new)
{
	new_layout(new,False);
	return (False);
}

static XtGeometryResult GeometryManager(Widget w, 
	XtWidgetGeometry *request, 
	XtWidgetGeometry *reply)
{
	new_layout((TabWidget)XtParent(w),True);
	return XtGeometryYes;
}

static void ChangeManaged(TabWidget tw)
{
	if(XtIsRealized((Widget)tw))
	  XClearArea(XtDisplay(tw),XtWindow(tw),0,0,0,0,True);
	new_layout(tw,True);
}


static void new_layout(TabWidget tw,Boolean geometry)
{
	int t;
	int i;
	Widget current = tw->tab.current;

	Dimension mw = 0;
	Dimension mh = 0;
	Dimension ww = 0;

	Dimension width  = tw->core.width;
	Dimension height = tw->core.height;

	tw->tab.title = 0;
	tw->tab.current = 0;


	for(i=0;i<tw->composite.num_children;i++)
	{
		Widget c = tw->composite.children[i];
		if(XtIsManaged(c))
		{
			XmString s = TAB_CONSTRAINT(c)->tab.name;
			int   h = XmStringHeight(tw->tab.font, s) + 2 * tw->tab.vmargin;
			int   w = XmStringWidth(tw->tab.font, s)  + 2 * tw->tab.hmargin;

			ww += w;

			mh  = MAX(mh,c->core.height);
			mw  = MAX(mh,c->core.width);

			tw->tab.title = MAX(tw->tab.title,h);

			if(c == current)
				tw->tab.current = c;

		}
	}

	if(tw->tab.drawer && !geometry )
		height = tw->tab.title;
	else
		height = tw->tab.title + tw->tab.top + tw->tab.bottom + mh;

	width  = 2 * tw->tab.hmargin + MAX(ww,mw);

    if(geometry)
    if(tw->core.width < width || tw->core.height < height)
    {
        Dimension           maxWidth = width, maxHeight = height;
        XtGeometryResult    result;
        Dimension           replyWidth = 0, replyHeight = 0;

        result = XtMakeResizeRequest(
            (Widget)tw,
            maxWidth,
            maxHeight,
            &replyWidth, &replyHeight);

        if (result == XtGeometryAlmost)
            XtMakeResizeRequest (
                (Widget)tw,
                replyWidth,
                replyHeight,NULL, NULL);
    }


	width  = tw->core.width;
	t      = (tw->tab.title + tw->tab.top + tw->tab.bottom);
	height = tw->core.height - t;

	for(i=0;i<tw->composite.num_children;i++)
	{
		Widget c = tw->composite.children[i];
		_XmConfigureObject((Widget)c,0,t,width,height,0);
	}

}

static void draw(TabWidget tw, Widget c,int* x,int* y,int k)
{
	XmString s = XmStringCopy(TAB_CONSTRAINT(c)->tab.name);
	XPoint points[10];
	int count = 4;
	int minx = 0;
	int maxx = 0;
	int xx = 0;
	int i;

	int sw    = XmStringWidth(tw->tab.font, s);
	int step  = sw + 2 * tw->tab.hmargin;
	int delta = 0;

	points[0].x = *x - tw->tab.hmargin / 2;
	points[0].y = tw->tab.title + tw->tab.top ;

	points[1].x = tw->tab.hmargin ;
	points[1].y = -tw->tab.title;

	points[2].x = sw + tw->tab.hmargin;
	points[2].y = 0;

	points[3].x = tw->tab.hmargin ;
	points[3].y = tw->tab.title;

	if(points[0].x + points[1].x + points[2].x + points[3].x > tw->core.width  )
	{
		int ww = 5;
		int xx = points[0].x + points[1].x;

		points[2].x = tw->core.width - xx - ww;
		points[2].y = 0;

		points[3].x = -ww;
		points[3].y = tw->tab.title / 3;

		points[4].x = ww;
		points[4].y = tw->tab.title / 3;

		points[5].x = -ww;
		points[5].y = tw->tab.title - 2 * (tw->tab.title / 3);

		count = 6;

		if(k < tw->tab.last)
			tw->tab.last = k;

		if(points[2].x < points[1].x)
		{
			(*x) += step;
			return;             /* outside window...? */
		}

	}


	if(points[0].x < 0)
	{
		int ww = 5;

		points[0].x = 0;
		points[0].y = tw->tab.title + tw->tab.top ;

		points[1].x = ww;
		points[1].y = -tw->tab.title / 3;

		points[2].x = -ww;
		points[2].y = -tw->tab.title / 3;

		points[3].x = ww;
		points[3].y = -tw->tab.title + 2 * (tw->tab.title / 3);

		points[4].x = *x - tw->tab.hmargin / 2 + 2*tw->tab.hmargin + sw - ww ;
		points[4].y = 0;

		points[5].x = tw->tab.hmargin ;
		points[5].y = tw->tab.title;

		count = 6;

		if(k > tw->tab.first)
			tw->tab.first = k;

		if(points[4].x < 0 )
		{
			(*x) += step;
			return;             /* outside window...? */
		}
	}

	minx = points[0].x;
	maxx = points[0].x;
	xx   = points[0].x;

	for(i = 1; i < count; i++)
	{
		xx += points[i].x;
		if(xx < minx) minx = xx;
		if(xx > maxx) maxx = xx;
	}
	
	XSetForeground(XtDisplay(tw),
		tw->tab.gc,
		(c == tw->tab.current) ? 
			tw->core.background_pixel:
			tw->tab.back);
		
	XFillPolygon(
		XtDisplay(tw),
		XtWindow(tw),
		tw->tab.gc,
		points,
		count,
		Convex,
		CoordModePrevious
	);

	XSetForeground(XtDisplay(tw),
		tw->tab.gc,
		tw->manager.foreground);

	XDrawLines(
		XtDisplay(tw),
		XtWindow(tw),
		/* tw->tab.gc, */
		tw->manager.bottom_shadow_GC,
		points,
		count,
		CoordModePrevious
	);

	XSetForeground(XtDisplay(tw),
		tw->tab.gc,
		(c == tw->tab.current) ? 
			tw->tab.blue:
			tw->manager.foreground);

	{
	    int   sl    = 0;
	    char* c_str = 0;
	    char  tmp_cstr[250];

	    if( XmStringGetLtoR( s, XmFONTLIST_DEFAULT_TAG, &c_str ) )
	      {
		sl = strlen( c_str );        /* true string length */
		strcpy( tmp_cstr, c_str );
		XtFree( c_str );
	      }

	    while( --sl >= 0 && sw > (maxx - minx - 2 * tw->tab.hmargin) )
	      {
		XmString t;                  /* tab name too long, thus...   */
		tmp_cstr[ sl ] = '\0';       /* ...truncate original name and */
		strcat( tmp_cstr, "..." );   /* append '...' to truncated name */

		t = XmStringCreate( tmp_cstr, XmFONTLIST_DEFAULT_TAG );

		XmStringFree(s);             /* replace s with freshly... */
		s = t;                       /* ...truncated compound string */
		sw = XmStringWidth(tw->tab.font, s);
#if 0
		printf( " %s/%d >? %d\n", tmp_cstr, sw, (maxx - minx - 2 * tw->tab.hmargin) );
#endif
	      }

	    XmStringDraw(XtDisplay(tw),
		XtWindow(tw),
		tw->tab.font,
		s,
		tw->tab.gc,
		minx ,
		tw->tab.vmargin + tw->tab.top + tw->tab.vmargin/3,
		maxx - minx,
		XmALIGNMENT_CENTER,
		XmSTRING_DIRECTION_L_TO_R,
		NULL);
	}

	XSetForeground(XtDisplay(tw),
		tw->tab.gc,
		tw->manager.foreground);

	XmStringFree(s);

	(*x) += step;
}

static void ReDisplay(Widget w, XEvent *event, Region region)
{
	TabWidget tw = (TabWidget)w;

	int x = tw->tab.delta;
	int y = 0;
	int i;
	int cx = 0,cy= 0, ci = 0;

	tw->tab.first = -1;
	tw->tab.last  = tw->composite.num_children + 1;

	for(i=0;i<tw->composite.num_children;i++)
	{
		Widget c = tw->composite.children[i];
		if(XtIsManaged(c))
		{

			if(!tw->tab.current) tw->tab.current = c;

			if(c == tw->tab.current)
			  { cx = x; cy = y; ci = i; }
			draw(tw,c,&x,&y,i);
		}
	}

	if(tw->tab.current)
	{
		GC gc = tw->tab.gc;
		int t = tw->tab.title + tw->tab.top;

		x = cx;
		y = cy;

		draw(tw,tw->tab.current,&x,&y,ci);

		/*========================*/

		XSetForeground(XtDisplay(tw),gc,
			tw->core.background_pixel);

		XDrawLine(XtDisplay(tw),
			XtWindow(tw),
			gc, 0, t, tw->core.width, t);

		XSetForeground(XtDisplay(tw),
			tw->tab.gc,
			tw->manager.foreground);

		/*========================*/

		gc = tw->manager.bottom_shadow_GC;

		XDrawLine(XtDisplay(tw),
			XtWindow(tw),
			gc,
			0,
			t,
			cx - tw->tab.hmargin/2,
			t);

		XDrawLine(XtDisplay(tw),
			XtWindow(tw),
			gc,
			x + tw->tab.hmargin/2,
			t,
			tw->core.width,
			t);
	}

	if(tw->tab.current && XtIsRealized(tw->tab.current))
		XRaiseWindow(XtDisplay(tw->tab.current),XtWindow(tw->tab.current));

	tw->tab.wait = False;
}


Widget CreateTab(Widget par,char* nam,Arg* al,int ac)
{
	return XtCreateWidget(nam,tabWidgetClass,par,al,ac);
}

Widget TabGetCurrent(Widget w)
{
	TabWidget tw = (TabWidget)w;
	return tw->tab.current;
}

static int opened_size(TabWidget tw)
{
	XtWidgetGeometry preferred;
	int size;

	XtQueryGeometry(tw->tab.current,NULL,&preferred);

	if((preferred.request_mode & CWHeight) != 0)
		size = preferred.height;
	else
		size = tw->tab.current->core.height;

	if(size < 40) size = 40;

	return size + tw->tab.title + tw->tab.vmargin;
}

static void open_close_tab(TabWidget tw)
{
	if(tw->core.height == tw->tab.title)
		XtVaSetValues((Widget)tw,XmNheight,opened_size(tw),NULL);
	else
		XtVaSetValues((Widget)tw,XmNheight,tw->tab.title,NULL);
}

static void open_full(TabWidget tw)
{
	int size = opened_size(tw);
	if(tw->core.height < size)
		XtVaSetValues((Widget)tw,XmNheight,size,NULL);
}

static void set_tab(Widget w,Widget c,Boolean tell,XEvent* ev)
{
	TabWidget tw = (TabWidget)w;
	TabCallbackStruct cb;
	Widget p;

	while(c && XtParent(c) != w)
		c = XtParent(c);

	if(!c) return;

	if(tw->tab.current == c)
	{
		if(tw->tab.drawer && !tw->tab.drag) 
			if(ev)
				open_close_tab(tw);
			else
				open_full(tw);
		return;
	}



	cb.reason = XmCR_VALUE_CHANGED;
	cb.widget = c;
	cb.event  = ev;

	if(tell) 
		XtCallCallbacks(w, XmNvalueChangedCallback, &cb);

	tw->tab.current = cb.widget;

	if(tw->tab.drawer) 
		open_full(tw);


	p = w;
	while(p && XtIsManaged(p)) p = XtParent(p);
	
	if(p == 0)  /* All parent are managed */
		make_visible(tw,tw->tab.current);

	if(XtIsRealized(w))
		XClearArea(XtDisplay(w),XtWindow(w),0,0,0,0,True);
}

void TabSetCurrent(Widget w,Widget c,Boolean tell)
{
	Widget p = XtParent(w);
	if(XtIsTab(p)) TabSetCurrent(p,w,tell);
	set_tab(w,c,tell,NULL);
}

void TabOpen(Widget w)
{
	open_full((TabWidget)w);
}

void TabClose(Widget w)
{
	TabWidget tw = (TabWidget)w;
	new_layout(tw,True);
	XtVaSetValues(w,XmNheight,tw->tab.title,NULL);
}

Boolean TabClosed(Widget w)
{
	TabWidget tw = (TabWidget)w;
	return tw->tab.title == tw->core.height;
}

static void Click(Widget w, XEvent *event, String *params,Cardinal *nparams)
{
	TabWidget tw = (TabWidget)w;
	int x = tw->tab.delta;
	int y = 0;
	int i;

	tw->tab.drag   = False;
	tw->tab.last_x = event->xbutton.x;
	tw->tab.last_y = event->xbutton.y;
	tw->tab.wait   = False;

#if 0

	for(i=0;i<tw->composite.num_children;i++)
	{
		Widget c = tw->composite.children[i];
		if(XtIsManaged(c))
		{
			XmString s = TAB_CONSTRAINT(c)->tab.name;

			int   h = XmStringHeight(tw->tab.font, s) + 2 * tw->tab.vmargin;
			int   w = XmStringWidth(tw->tab.font, s)  + 2 * tw->tab.hmargin;


			if(event->xbutton.y >= tw->tab.top && 
			   event->xbutton.y <= h + tw->tab.top)
				if(event->xbutton.x >= x && event->xbutton.x <= x + w)
				{

					if(i <= tw->tab.first || i>= tw->tab.last)
						make_visible(tw,c);
					else
						set_tab((Widget)tw,c,True,event);
					break;
				}
			x += w;
		}
	}

#endif

}

static void Drag(Widget w, XEvent *event, String *params,Cardinal *nparams)
{
	TabWidget tw = (TabWidget)w;
	int h = tw->core.height;

	if(!tw->tab.drawer) return;
	if(tw->tab.wait) return;

	tw->tab.drag = True;
	tw->tab.wait = True;

	h += tw->tab.last_y - event->xbutton.y;

	if(h < tw->tab.title ) h = tw->tab.title;


	XtVaSetValues((Widget)tw,XmNheight,h,NULL);
}

static void Release(Widget w, XEvent *event, String *params,Cardinal *nparams)
{
#if 1
	TabWidget tw = (TabWidget)w;

	int x = tw->tab.delta;
	int y = 0;
	int i;

	/* if(tw->tab.drag) return; */
	/* if(!tw->tab.drawer) return; */

	for(i=0;i<tw->composite.num_children;i++)
	{
		Widget c = tw->composite.children[i];
		if(XtIsManaged(c))
		{
			XmString s = TAB_CONSTRAINT(c)->tab.name;

			int   h = XmStringHeight(tw->tab.font, s) + 2 * tw->tab.vmargin;
			int   w = XmStringWidth(tw->tab.font, s)  + 2 * tw->tab.hmargin;


			if(event->xbutton.y >= tw->tab.top && 
			   event->xbutton.y <= h + tw->tab.top)
				if(event->xbutton.x >= x && event->xbutton.x <= x + w)
				{

					if(i <= tw->tab.first || i>= tw->tab.last)
						make_visible(tw,c);
					else
						set_tab((Widget)tw,c,True,event);
					break;
				}
			x += w;
		}
	}
#endif

	tw->tab.drag = False;
}


static void make_visible(TabWidget tw, Widget wid)
{
	int x = 0;
	int i;
	int m = 0;
	int j = 0;

	int from,to;

	int* pos = (int*)XtCalloc(sizeof(int),tw->composite.num_children+1);

	if (tw->composite.num_children == 0)
	      return;

	for(i=0;i<tw->composite.num_children;i++)
	{
		Widget c = tw->composite.children[i];
		if(XtIsManaged(c))
		{
			XmString s = TAB_CONSTRAINT(c)->tab.name;

			int   h = XmStringHeight(tw->tab.font, s) + 2 * tw->tab.vmargin;
			int   w = XmStringWidth(tw->tab.font, s)  + 2 * tw->tab.hmargin; 

			if(c == wid)
				j = m;
			pos[m++] = x;
			x += w;
		}
	}

	pos[m] = x;

	if(j == 0 || j == m-1)
	{
		from = pos[j]   - tw->tab.hmargin;
		to   = pos[j+1] + tw->tab.hmargin;;
	}
	else {
		from = (pos[j]+pos[j-1])/2;
		to   = (pos[j+2]+pos[j+1])/2;
	}

	if(from + tw->tab.delta < 0)
	{
		tw->tab.delta = -from;	
		if(XtIsRealized((Widget)tw))
			XClearArea(XtDisplay(tw),XtWindow(tw),0,0,0,0,True);
	}

	if(to + tw->tab.delta > tw->core.width )
	{
		tw->tab.delta = -(to-tw->core.width);
		if(XtIsRealized((Widget)tw))
			XClearArea(XtDisplay(tw),XtWindow(tw),0,0,0,0,True);
	}


	XtFree((XtPointer)pos);
}

void TabSetName(Widget tw,Widget w,const char* name)
{
	XmStringFree(TAB_CONSTRAINT(w)->tab.name);
	TAB_CONSTRAINT(w)->tab.name = XmStringCreateSimple((char*)name);

	if(XtIsRealized(tw))	XClearArea(XtDisplay(tw),XtWindow(tw),0,0,0,0,True);
	new_layout((TabWidget)tw,True);
}
