/**
 *
 * $Id: Container.c,v 1.7 1999/10/26 22:22:19 danny Exp $
 *
 * Copyright (C) 1997-1999 Free Software Foundation, Inc.
 *
 * This file is part of the GNU LessTif Library.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **/

#include <LTconfig.h>
#include <XmI/XmI.h>

#include <Xm/XmP.h>
#include <Xm/BaseClassP.h>
#include <Xm/Container.h>
#include <Xm/ContainerP.h>
#include <Xm/ContainerT.h>

#include <XmI/DebugUtil.h>


/* 
  MODULE:	Container.c
  DESCRIPTION:	Implement the XmContainer widget class.
  STATUS:	Not too well yet.
  END:
*/

/*
 * Forward Declarations
 */

static void class_part_initialize(WidgetClass widget_class);
static void Initialize(Widget request, Widget new_w, ArgList args, Cardinal *num_args);
static void resize(Widget w);
static Boolean SetValues(Widget current, Widget request, Widget new_w, ArgList args, Cardinal *num_args);
static void expose(Widget w, XEvent *event, Region region);
static XtGeometryResult QueryGeometry(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply);
static void _XmContainerLayout(Widget w, Dimension *pwid, Dimension *pht);

/* composite */
static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply);
static void ChangeManaged(Widget w);

/* constraint */
static void ConstraintInitialize(Widget request, Widget new_w, ArgList args, Cardinal *num_args);
static void ConstraintDestroy(Widget w);
static Boolean ConstraintSetValues(Widget current, Widget request, Widget new_w, ArgList args, Cardinal *num_args);

/*
 * resources for the Container class
 */
#define Offset(field) XtOffsetOf(XmContainerRec, container.field)
static XtResource resources[] =
{
    {
	XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension,
	sizeof(Dimension), Offset(margin_h),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension,
	sizeof(Dimension), Offset(margin_w),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNautomaticSelection, XmCAutomaticSelection, XmRChar,
	sizeof(unsigned char), Offset(automatic),
	XmRImmediate, (XtPointer)XmAUTO_SELECT
    },
    {
	XmNcollapsedStatePixmap, XmCCollapsedStatePixmap, XmRPixmap,
	sizeof(Pixmap), Offset(collapsed_state_pixmap),
	XmRImmediate, (XtPointer)0	/* FIXME default should be dynamic */
    },
    {
	XmNconvertCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(convert_cb),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNdefaultActionCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(default_action_cb),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNdestinationCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(destination_cb),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNdetailColumnHeading, XmCDetailColumnHeading, XmRXmStringTable,
	sizeof(XmStringTable), Offset(detail_heading),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNdetailColumnHeadingCount, XmCDetailColumnHeadingCount, XmRCardinal,
	sizeof(Cardinal), Offset(detail_heading_count),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNdetailOrder, XmCDetailOrder, XmRCardinalList,
	sizeof(Cardinal *), Offset(detail_order),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNdetailOrderCount, XmCDetailOrderCount, XmRCardinal,
	sizeof(Cardinal), Offset(detail_order_count),
	XmRImmediate, (XtPointer)0	/* FIXME should be dynamic */
    },
    {
	XmNdetailTabList, XmCDetailTabList, XmRTabList,
	sizeof(XmTabList), Offset(detail_tablist),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNentryViewType, XmCEntryViewType, XmRChar,
	sizeof(unsigned char), Offset(entry_viewtype),
	XmRImmediate, (XtPointer)XmANY_ICON
    },
    {
	XmNexpandedStatePixmap, XmCExpandedStatePixmap, XmRPixmap,
	sizeof(Pixmap), Offset(expanded_state_pixmap),
	XmRImmediate, (XtPointer)0	/* FIXME should be dynamic */
    },
#if 0
    {
	XmNfontList, XmCFontList, XmRFontList,
	sizeof(XmFontList), Offset(fontlist),
	XmRImmediate, (XtPointer)0
    },
#endif
    {
	XmNlargeCellHeight, XmCCellHeight, XmRDimension,
	sizeof(Dimension), Offset(large_cell_height),
	XmRImmediate, (XtPointer)0	/* FIXME should be dynamic */
    },
    {
	XmNlargeCellWidth, XmCCellWidth, XmRDimension,
	sizeof(Dimension), Offset(large_cell_width),
	XmRImmediate, (XtPointer)0	/* FIXME should be dynamic */
    },
    {
	XmNlayoutType, XmCLayoutType, XmRChar,
	sizeof(unsigned char), Offset(layout_type),
	XmRImmediate, (XtPointer)XmSPATIAL
    },
    {
	XmNoutlineButtonPolicy, XmCOutlineButtonPolicy, XmRChar,
	sizeof(unsigned char), Offset(ob_policy),
	XmRImmediate, (XtPointer)XmOUTLINE_BUTTON_PRESENT
    },
    {
	XmNoutlineChangedCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(outline_cb),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNoutlineColumnWidth, XmCOutlineColumnWidth, XmRDimension,
	sizeof(Dimension), Offset(ob_width),
	XmRImmediate, (XtPointer)0	/* FIXME should be dynamic */
    },
    {
	XmNoutlineIndentation, XmCOutlineIndentation, XmRDimension,
	sizeof(Dimension), Offset(outline_indent),
	XmRImmediate, (XtPointer)40
    },
    {
	XmNoutlineLineStyle, XmCLineStyle, XmRChar,
	sizeof(unsigned char), Offset(outline_sep_style),
	XmRImmediate, (XtPointer)XmSINGLE
    },
    {
	XmNprimaryOwnership, XmCPrimaryOwnership, XmRChar,
	sizeof(unsigned char), Offset(primary_ownership),
	XmRImmediate, (XtPointer)XmOWN_POSSIBLE_MULTIPLE
    },
    {
	XmNrenderTable, XmCRenderTable, XmRRenderTable,
	sizeof(XmRenderTable), Offset(render_table),
	XmRImmediate, (XtPointer)0	/* FIXME should be dynamic */
    },
    {
	XmNselectColor, XmCSelectColor, XmRPixel,
	sizeof(Pixel), Offset(select_color),
	XmRImmediate, (XtPointer)0	/* FIXME should be dynamic */
    },
    {
	XmNselectedObjects, XmCSelectedObjects, XmRWidgetList,
	sizeof(WidgetList), Offset(selected_items),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNselectedObjectCount, XmCSelectedObjectCount, XmRInt,
	sizeof(unsigned int), Offset(selected_item_count),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNselectionCallback, XmCCallback, XmRCallback,
	sizeof(XtCallbackList), Offset(selection_cb),
	XmRImmediate, (XtPointer)0
    },
    {
	XmNselectionPolicy, XmCSelectionPolicy, XmRChar,
	sizeof(unsigned char), Offset(selection_policy),
	XmRImmediate, (XtPointer)XmEXTENDED_SELECT
    },
    {
	XmNselectionTechnique, XmCSelectionTechnique, XmRChar,
	sizeof(unsigned char), Offset(selection_technique),
	XmRImmediate, (XtPointer)XmTOUCH_OVER
    },
    {
	XmNsmallCellHeight, XmCCellHeight, XmRDimension,
	sizeof(Dimension), Offset(small_cell_height),
	XmRImmediate, (XtPointer)0	/* FIXME should be dynamic */
    },
    {
	XmNsmallCellWidth, XmCCellWidth, XmRDimension,
	sizeof(Dimension), Offset(small_cell_width),
	XmRImmediate, (XtPointer)0	/* FIXME should be dynamic */
    },
    {
	XmNspatialIncludeModel, XmCSpatialIncludeModel, XmRChar,
	sizeof(unsigned char), Offset(include_model),
	XmRImmediate, (XtPointer)XmAPPEND
    },
    {
	XmNspatialResizeModel, XmCSpatialResizeModel, XmRChar,
	sizeof(unsigned char), Offset(resize_model),
	XmRImmediate, (XtPointer)XmGROW_MINOR
    },
    {
	XmNspatialSnapModel, XmCSpatialSnapModel, XmRChar,
	sizeof(unsigned char), Offset(snap_model),
	XmRImmediate, (XtPointer)XmNONE
    },
    {
	XmNspatialStyle, XmCSpatialStyle, XmRChar,
	sizeof(unsigned char), Offset(spatial_style),
	XmRImmediate, (XtPointer)XmGRID
    },
};


/* *INDENT-OFF* */
XmContainerClassRec xmContainerClassRec = {
    /* Core class part */
    {
	/* superclass            */ (WidgetClass) &xmManagerClassRec,
        /* class_name            */ "XmContainer",
	/* widget_size           */ sizeof(XmContainerRec),
	/* class_initialize      */ NULL /*class_initialize*/,
	/* class_part_initialize */ class_part_initialize,
	/* 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     */ XtExposeCompressMaximal,
	/* compress_enterleave   */ True,
	/* visible_interest      */ False,
	/* destroy               */ NULL,
	/* resize                */ XtInheritResize,
	/* expose                */ expose,
	/* set_values            */ SetValues,
	/* set_values_hook       */ NULL,
	/* set_values_almost     */ XtInheritSetValuesAlmost,
	/* get_values_hook       */ NULL,
	/* accept_focus          */ NULL,
	/* version               */ XtVersion,
	/* callback offsets      */ NULL,
	/* tm_table              */ XtInheritTranslations,
	/* query_geometry        */ QueryGeometry,
	/* display_accelerator   */ NULL,
	/* extension             */ (XtPointer)NULL /*&_XmContainerCoreClassExtRec*/
    },
    /* Composite class part */
    {
	/* geometry manager */ GeometryManager, 
        /* change_managed   */ ChangeManaged, 
        /* insert_child     */ XtInheritInsertChild,
        /* delete_child     */ XtInheritDeleteChild,
        /* extension        */ (XtPointer)NULL
    },
    /* Constraint class part */
    {
	/* subresources      */ NULL /*containerConstraintResources*/,
        /* subresource_count */ 0 /*XtNumber(containerConstraintResources)*/, 
        /* constraint_size   */ 0 /*sizeof(XmContainerConstraintRec)*/,
        /* initialize        */ ConstraintInitialize,
        /* destroy           */ ConstraintDestroy,
        /* set_values        */ ConstraintSetValues,
        /* extension         */ NULL,  
    },
    /* XmManager class part */
    {
	/* translations                 */ XtInheritTranslations,
        /* syn_resources                */ NULL,
        /* num_syn_resources            */ 0,
        /* syn_constraint_resources     */ NULL,
        /* num_syn_constraint_resources */ 0,
        /* parent_process               */ XmInheritParentProcess,
	/* extension                    */ (XtPointer)NULL
    },
    /* XmContainer Area part */
    {
	/* extension */ NULL,
    },
};
/* *INDENT-ON* */

WidgetClass xmContainerWidgetClass = (WidgetClass)&xmContainerClassRec;

Widget
XmCreateContainer(Widget parent, String name, ArgList arglist, Cardinal argcount)
{
   return XtCreateWidget(name, xmContainerWidgetClass, parent, arglist, argcount);
}

static void class_part_initialize(WidgetClass widget_class)
{
	/* FIXTHIS: Needs to be implemented */
	DEBUGOUT(XdbDebug(__FILE__, NULL, "XmContainer class_part_initialize\n"));
}

static void
Initialize(Widget request, Widget new_w, ArgList args, Cardinal *num_args)
{
	Dimension	wid, ht;
	/* FIXTHIS: Needs to be implemented */
	DEBUGOUT(XdbDebug(__FILE__, new_w, "XmContainer initialize\n"));
	_XmContainerLayout(new_w, &wid, &ht);

	XtWidth(new_w) = (wid < 100) ? 100 : wid;
	XtHeight(new_w) = (ht < 100) ? 100 : ht;
}

static void
resize(Widget w)
{
	/* FIXTHIS: Needs to be implemented */
	DEBUGOUT(XdbDebug(__FILE__, w, "XmContainer resize\n"));
}


static Boolean
SetValues(Widget current, Widget request, Widget new_w, ArgList args, Cardinal *num_args)
{
	/* FIXTHIS: Needs to be implemented */
	DEBUGOUT(XdbDebug(__FILE__, new_w, "XmContainer SetValues\n"));
	return True;
}

static void
expose(Widget w, XEvent *event, Region region)
{
	DEBUGOUT(XdbDebug(__FILE__, w, "XmContainer expose\n"));
	/* FIXTHIS: Needs to be implemented */

	_XmRedisplayGadgets(w, event, region);

}

/*
 * FIX ME this is simplistic
 */
static void
_XmContainerLayout(Widget w, Dimension *pwid, Dimension *pht)
{
	Dimension	wid, ht;
	int		i;
	Position	x, y;

	wid = ContainerMarginWidth(w);
	ht = 0;

	for (i=0; i<MGR_NumChildren(w); i++) {
		Widget	child = MGR_Children(w)[i];
		if (XtIsManaged(child)) {
			wid += XtWidth(child) + ContainerMarginWidth(w);
			if (XtHeight(child) > ht)
				ht = XtHeight(child);
		}
	}

	ht += 2 * ContainerMarginHeight(w);

	if (pwid)
		*pwid = wid;
	if (pht)
		*pht = ht;

	x = ContainerMarginWidth(w);
	y = ContainerMarginHeight(w);
	for (i=0; i<MGR_NumChildren(w); i++) {
		Widget	child = MGR_Children(w)[i];
		if (XtIsManaged(child)) {
			_XmMoveObject(child, x, y);
			x += XtWidth(child) + ContainerMarginWidth(w);
		}
	}
}

static XtGeometryResult
QueryGeometry(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply)
{
	Dimension		wid, ht;
	XtWidgetGeometry	g;

	/* FIXTHIS: Needs to be implemented */

	DEBUGOUT(XdbDebug(__FILE__, w, "XmContainer QueryGeometry\n"));
	g = *request;

	_XmContainerLayout(w, &wid, &ht);

	wid = (request->request_mode & CWWidth) ?
		(request->width < wid) ? wid : request->width : wid;
	ht = (request->request_mode & CWHeight) ?
		(request->height < ht) ? ht : request->height : ht;

	reply->request_mode = CWWidth | CWHeight;
	reply->width = (wid == 0) ? 1 : wid;
	reply->height = (ht == 0) ? 1 : ht;

	return _XmGMReplyToQueryGeometry(w, &g, reply);
}

/* composite */
static XtGeometryResult
GeometryManager(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply)
{
	DEBUGOUT(XdbDebug(__FILE__, w, "XmContainer GeometryManager\n"));

	/* FIXTHIS: Needs to be implemented */
	*reply = *request;
	return XtGeometryYes;
}

static void
ChangeManaged(Widget w)
{
	DEBUGOUT(XdbDebug(__FILE__, w, "XmContainer ChangeManaged\n"));

	/* FIXTHIS: Needs to be implemented */
	_XmNavigChangeManaged(w);
	_XmContainerLayout(w, 0, 0);
}

/* constraint */
static void
ConstraintInitialize(Widget request, Widget new_w, ArgList args, Cardinal *num_args)
{
	/* FIXTHIS: Needs to be implemented */
	DEBUGOUT(XdbDebug2(__FILE__, XtParent(new_w), new_w, "XmContainer ConstraintInitialize\n"));

	_XmContainerLayout(XtParent(new_w), 0, 0);
}

static void
ConstraintDestroy(Widget w)
{
	/* FIXTHIS: Needs to be implemented */
	DEBUGOUT(XdbDebug(__FILE__, w, "XmContainer ConstraintDestroy\n"));
}

static Boolean
ConstraintSetValues(Widget current, Widget request, Widget new_w, ArgList args, Cardinal *num_args)
{
	DEBUGOUT(XdbDebug(__FILE__, new_w, "XmContainer ConstraintSetValues\n"));
	/* FIXTHIS: Needs to be implemented */
	_XmContainerLayout(XtParent(new_w), NULL, NULL);
	return True;
}
