#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include "ArrangeBoxP.h"

#define	InheritedProc(w,class,proc)	(((class)((w)->core.widget_class->core_class.superclass))->proc)

static int defArrange = ArrangeAscent;

#define ABOffset(tag) XtOffset(ArrangeBoxWidget, arrange_box.tag)

static XtResource resources[] = {
	{AiNvertNum, AiCVertNum, XtRInt, sizeof(int),
	 ABOffset(vert_num),XtRString,(caddr_t)"8"},
	{AiNarrangeOrder, AiCArrangeOrder, XtRInt, sizeof(int),
	 ABOffset(arrange_order), XtRInt, (caddr_t)&defArrange},
	{AiNresizeParent, AiCResizeParent, XtRBoolean, sizeof(Boolean),
	 ABOffset(resize_parent), XtRString, (caddr_t)"TRUE"},
};

static void
	Redisplay(),
	Resize(),
	Initialize(),
	InitializeClass(),
	InsertChild(),
	SortChildren();

ArrangeBoxClassRec arrangeBoxClassRec = {
/* core_class fields      */
{
    /* superclass         */    (WidgetClass) &boxClassRec,
    /* class_name         */    "ArrangeBox",
    /* widget_size        */    sizeof(ArrangeBoxRec),
    /* class_initialize   */    InitializeClass,
    /* class_part_init    */    NULL,
    /* class_inited       */    FALSE,
    /* initialize         */    Initialize,
    /* initialize_hook    */    NULL,
    /* realize            */    XtInheritRealize,
    /* actions            */    NULL,
    /* num_actions        */    0,
    /* resources          */    resources,
    /* num_resources      */    XtNumber(resources),
    /* xrm_class          */    NULLQUARK,
    /* compress_motion    */    TRUE,
    /* compress_exposure  */    TRUE,
    /* compress_enterleave*/    TRUE,
    /* visible_interest   */    FALSE,
    /* destroy            */    NULL,
    /* resize             */    XtInheritResize,
    /* expose             */    Redisplay,
    /* set_values         */    NULL,
    /* set_values_hook    */    NULL,
    /* set_values_almost  */    XtInheritSetValuesAlmost,
    /* get_values_hook    */    NULL,
    /* accept_focus       */    XtInheritAcceptFocus,
    /* version            */    XtVersion,
    /* callback_private   */    NULL,
    /* tm_table           */    NULL,
    /* query_geometry     */    XtInheritQueryGeometry,
},
{
/* composite_class fields */
    /* geometry_manager   */    XtInheritGeometryManager,
    /* change_managed     */    XtInheritChangeManaged,
    /* insert_child       */    InsertChild,
    /* delete_child       */    XtInheritDeleteChild,
    /* extension          */    NULL,
},
{
/* box_class fields */
    /* empty              */	NULL,
},
{
/* ArrangeBox class fields */
    /* sort_children	  */	SortChildren,
}
};

WidgetClass	arrangeBoxWidgetClass = (WidgetClass)&arrangeBoxClassRec;

#define ACCESS_SUPER(w,tag) (XtSuperclass(w)->tag)
#define CALL_SUPER(w,cmd,arg) (*ACCESS_SUPER(w,core_class.cmd))arg

/* Methods */
/*
 * Class initialization
 */
static void
InitializeClass()
{
	ArrangeBoxWidgetClass wc = (ArrangeBoxWidgetClass)arrangeBoxWidgetClass;
	
	if (wc->arrange_box_class.sort_children == AiInheritSortChildren) {
		wc->arrange_box_class.sort_children =
			((ArrangeBoxWidgetClass)wc->core_class.superclass)->
				arrange_box_class.sort_children;
	}
}

/*
 * Initialize
 */
static void
Initialize(w)
ArrangeBoxWidget w;
{
}

/*
 * Sort children by name
 */
static void
SortChildren(w)
ArrangeBoxWidget w;
{
	int i,j,num,swap;
	WidgetList ch;
	Widget tmp;
	
	num = w->composite.num_children;
	ch = w->composite.children;
	for (i = 0; i < num; i++) {
		for (j = 0; j < num; j++) {
			if (w->arrange_box.arrange_order == ArrangeAscent)
				swap = (strcmp(ch[i]->core.name,ch[j]->core.name) < 0);
			else
				swap = (strcmp(ch[i]->core.name,ch[j]->core.name) > 0);
			if (swap) {
				tmp = ch[i];
				ch[i] = ch[j];
				ch[j] = tmp;
			}
		}
	}
}

/*
 * Redisplay method
 */
static void
Redisplay(wig)
Widget wig;
{
	ArrangeBoxWidget w = (ArrangeBoxWidget)wig;

	AiSortChildren(w);
}

static void
RearrangeSize(wig)
Widget wig;
{
	ArrangeBoxWidget w = (ArrangeBoxWidget)wig;
	int i,j,wd,hg,h,width,height;
	int vn = w->arrange_box.vert_num;
	int num = w->composite.num_children;
	WidgetList ch = w->composite.children;

	width = w->box.h_space;
	height = 0;
	wd = w->box.h_space;
	hg = 0;
	j = 0;
	for (i = 0; i < num; i++) {
		j++;
		if ( j > vn ) {
			if (width < wd)
				width = wd;
			height += hg+w->box.v_space;
			wd = w->box.h_space;
			hg = 0;
			j = 0;
		}
		ch[i]->core.x = wd;
		ch[i]->core.y = height;
		wd += ch[i]->core.width +
			ch[i]->core.border_width*2 +
				w->box.h_space;
		if (hg < (h = ch[i]->core.height+ ch[i]->core.border_width*2))
			hg = h;
	}
	if (width < wd)
		width = wd;
	height += hg+w->box.v_space;
	if (w->core.width != width || w->core.height != height) {
		w->core.width = width;
		w->core.height = height;

		if (w->arrange_box.resize_parent) {
			XtResizeWidget(w->core.parent,
				       width+w->core.border_width*2,
				       height+w->core.border_width*2,
				       w->core.parent->core.border_width);
			XtResizeWindow(w->core.parent);
		}
		XtResizeWidget(w,width,height,w->core.border_width);
		XtResizeWindow(w);
	}
}

/*
 * Insert child method
 */
static void
InsertChild(w,arg,num_args)
Widget w;
ArgList arg;
Cardinal *num_args;
{
	ArrangeBoxWidget ab;

	ab = (ArrangeBoxWidget)w->core.parent;
	(*((CompositeClassRec*)XtSuperclass(ab))->composite_class.insert_child)(w,arg,num_args);
	RearrangeSize(ab);
}
	

/* Utility functions */
/*
 * Find a child which have the specified name.
 */
Widget
AiFindWidgetByName(w,name)
ArrangeBoxWidget w;
char *name;
{
	int i;
	WidgetList ch = w->composite.children;
	
	for (i = 0; i < w->composite.num_children; i++) {
		if (!strcmp(ch[i]->core.name,name))
			return ch[i];
	}
	return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1