/* $Id: Row.c,v 1.1 1997/04/15 10:09:47 archer Exp $
 *	ROW.C - Specific form with horizontally laid widgets
 */
#include <Widget/FormP.h>


/**
 ** Internal:ROW_RECURSIVE_RESIZE
 **	Recursively change the various widgets
 **/
static int row_recursive_resize(X11_widget row, X11_widget o,
							int x, int margin)
{
int	y;
int	w, h;
int	d;
int	b;
/*
 * End of recursion
 */
	b = row->border2;
	if (o == 0)
		return row->w - (b + x + margin);
	if (o->unmanaged)
		return row_recursive_resize(row, o->sibling, x, margin);
/*
 * Add the margin around widget
 */
	if (margin < o->margin_w)
		margin = o->margin_w;
	x += margin;
	margin = o->margin_w;
/*
 * Guess Y position
 */
	if ((y = o->hint_y) != 0) {
		if (y < 0)
			y += row->h - (b + o->h_min);
	} else
		y = o->margin_h;
/*
 * Guess heigth
 */
	if (o->fixed_h)
		h = o->h_min;
	else
		h = row->h - (b+ y + o->margin_h);
/*
 * Correct Y position
 */
	if (!o->hint_y)
		y = (row->h - (b + h)) / 2;
/*
 * Resize widget...
 */
	if (!h)
		h = 1 + o->border2;
	if (h != o->h) {
		o->h = h;
		(*o->on_resize_window)(o, (XEvent *)0);
	}
/*
 * Move widget
 */
	if (x != o->x || y != o->y) {
		o->x = x;
		o->y = y;
		if (o->id)
			XMoveWindow(x11__screen, o->id, x, y);
	}
	x += o->w;
/*
 * Width resize needed?
 */
	d = row_recursive_resize(row, o->sibling, x, margin);
	if (d == 0)
		return 0;
	w = o->w;
	if (!o->fixed_w)
		w += d;
	if (w < o->w_min)
		w = o->w_min;
	d += o->w - w;
/*
 * Resized?
 */
	if (o->w != w) {
		o->w = w;
		(*o->on_resize_window)(o, (XEvent *)0);
	}
	if (d) {
		o->x += d;
		if (o->id)
			XMoveWindow(x11__screen, o->id, o->x, o->y);
	}
	return d;
}


/**
 ** Internal:ROW_RESIZE
 **	Geometry of a row has changed...
 **/
static void row_resize(X11_widget wdg, XEvent *dummy)
{
/*
 * Resize the XWindow object
 */
	x11__core_resize(wdg, dummy);
/*
 * Now, apply recursively the moves & resizes
 */
	(void)row_recursive_resize(wdg, wdg->child, 0, 0);
}


/**
 ** Internal:ROW_GEOMETRY
 **	Apply geometry from a row
 **/
static void row_geometry(X11_widget wdg, XEvent *dummy)
{
X11_widget	child;
unsigned int	w, w_min;
unsigned int	h, h_min;
unsigned int	margin;
unsigned int	value;
int		y;
/*
 * Initialisations
 */
	margin = 0;
	w = w_min = 0;
	h = h_min = 0;
	wdg->fixed_w = True;
	wdg->fixed_h = True;
/*
 * Each child is scanned for this...
 */
	for (child = wdg->child; child; child = child->sibling) {
		if (child->unmanaged)
			continue;
		(*child->on_geometry_check)(child, dummy);
/*
 * What has the child to say?
 */
		if (!child->fixed_w)
			wdg->fixed_w = False;
		if (!child->fixed_h)
			wdg->fixed_h = False;
		if (margin < child->margin_w)
			margin = child->margin_w;
		w     += margin + child->w;
		w_min += margin + child->w_min;
/*
 * New margin applicable
 */
		margin = child->margin_w;
		if ((y = child->hint_y) == 0)
			y = child->margin_h;
		if (y < 0)
			y = child->margin_h - y;
		else
			y += child->margin_h;
/*
 * Now, new widths
 */
		value = child->h + y;
		if (value > h)
			h = value;
		value = child->h_min + y;
		if (value > h_min)
			h_min = value;
	}
	w     += margin;
	w_min += margin;
/*
 * Then, check the sizes...
 */
	if (w_min < 1)
		w_min = 1;
	if (w < w_min)
		w = w_min;
	if (h_min < 1)
		h_min = 1;
	if (h < h_min)
		h = h_min;
	w     += wdg->border2;
	h     += wdg->border2;
	w_min += wdg->border2;
	h_min += wdg->border2;
/*
 * Apply new geometry
 */
	wdg->w_min = w_min;
	wdg->h_min = h_min;
	if (wdg->w >= w_min && !wdg->fixed_w)
		w = wdg->w;
	if (wdg->h >= h_min && !wdg->fixed_h)
		h = wdg->h;
	if (wdg->w != w || wdg->h != h) {
		wdg->w = w;
		wdg->h = h;
		row_resize(wdg, dummy);
	}
}


/**
 ** XWIDGET_ROW
 **	Create a row window
 **/
X11_widget X11_Row(X11_widget parent, char *name)
{
x11__form	*object;
/*
 * Default name
 */
	if (!name)
		name = "row";
/*
 * Get resource
 */
	object = allocator(x11__form);
	x11__core_setup(&object->core, parent, "Row", name);
/*
 * Initialize fields
 */
	object->core.on_geometry_check = row_geometry;
	object->core.on_resize_window  = row_resize;
	x11__resource_basic(&object->core);
/*
 * Special look and feel initializations
 */
	object->core.is_active  = parent->is_active;
	object->core.can_active = parent->can_active;
/*
 * Ok
 */
	return OBJECT_P;
}
