/*
 ******************************************************************************
 *
 *	ParcPlace Systems, Inc.
 *	Copyright (c) 1990, ParcPlace Systems, Inc. USA   All rights reserved.
 *
 ****************************************************************************
 *
 *	File:	layout.H
 *
 *	Functions(s):
 *
 *	Description:
 *		OI_layout_method class header
 *
 *	RCSid = "$Id: layout.H,v 4.20.1.2 1993/06/02 19:13:46 imp Exp $"
 *
 ****************************************************************************
 */

#ifndef OI_layout_H
#define OI_layout_H

#ifndef OI_defs_H
#include <OI/defs.H>
#endif /* OI_defs_H */

#ifndef OI_class_H
#include <OI/class.H>		/* needed for OI_make_minimal_memfnp */
#endif /* OI_class_H */

		const	OI_number		OI_lm_default_stretch = 1000 ;				/* default glue stretchability */

		class	OI_class ;
		class	OI_d_tech ;
		class	OI_layout_slot ;
		class	OI_lm_box ;
		class	OI_lm_glue ;
		class	OI_lm_obj_box ;
		class	OI_layout_method ;
		class	OI_layout_geometry_spec ;	// virtual base for geometry specifications, if can't fit in cast to void*

#define			OI_temp_position	(OI_undefined-1)					/* temp (when fetching row, col not yet fetched) psn */

	extern		OI_class		*OI_register_layout_method(const char*,const char*,OI_make_minimal_memfnp) ;	/* register a layout function */

		class	OI_layout_slot : public OI_callback	{								/* generic object layout slot */
			OI_layout_slot		*nxt;							/* pointer to next slot */
			OI_layout_slot		*prv;							/* pointer to previous slot */
			OI_lm_box		*hdrp;							/* back pointer to the head of the list */
		 protected:
		 public:
						OI_layout_slot() ;
		virtual				~OI_layout_slot() ;
		virtual	OI_bool			gravity_space_sizetrack_adjust(OI_bool*,OI_bool*) ;	/* adjust glue / box for gravity, size_tracking */
			OI_lm_box		*head() const				{ return(hdrp); }
		virtual	OI_bool			is_glue() const ;
		virtual	OI_layout_method	*layout_method() const ;				/* get ptr to layout method containing this object */
			OI_layout_slot		*next() const				{ return(nxt); }
		virtual	OI_lm_box		*next_box(const OI_layout_slot*) const ;
		virtual	void			minimum_size(OI_number*,OI_number*) const = 0 ;
		virtual	OI_number		minimum_size_x() const = 0 ;
		virtual	OI_number		minimum_size_y() const = 0 ;
		virtual	void			nominal_size(OI_number*,OI_number*) const = 0 ;
		virtual	OI_number		nominal_size_x() const = 0 ;
		virtual	OI_number		nominal_size_y() const = 0 ;
		virtual	OI_d_tech		*object() const ;
		virtual	long			origin_x() const = 0 ;
		virtual	long			origin_y() const = 0 ;
		virtual	OI_number		position() const ;					/* ordinal position of box; -1 => glue */
			OI_layout_slot		*prev() const				{ return(prv); }
		virtual	OI_lm_box		*prev_box(const OI_layout_slot*) const ;
			void			set_head(OI_lm_box *sp)			{ hdrp=sp; }
			void			set_next(OI_layout_slot *sp)		{ nxt=sp; }
		virtual	void			set_origin(long, long) ;
			void			set_prev(OI_layout_slot *sp)		{ prv=sp; }
		virtual	void			set_size(OI_number w, OI_number h) = 0 ;
		virtual	void			size_change() ;						/* obj size change, update layout consistency */
		virtual	OI_number		size_x() const = 0 ;
		virtual	OI_number		size_y() const = 0 ;
		virtual	OI_number		stretch_x() const = 0 ;
		virtual	OI_number		stretch_y() const = 0 ;
		virtual	void			unlink() ;
		} ;

		class	OI_lm_box : public OI_layout_slot {					/* slot for box in layout */
			OI_layout_slot		*slotp ;						/* ptr to list of kids */
			OI_origin		psn;							/* location */
			OI_xy			strtch ;						/* stretchability */
			OI_xy			siz;							/* space occupied by slot */
			OI_number		val;							/* what row/col this slot is in */
		 protected:
		 public:
						OI_lm_box() ;
		virtual				~OI_lm_box();
			void			append(OI_layout_slot*,OI_layout_slot*) ;		/* append new item after existing one */
		virtual	OI_gravity		gravity() const = 0 ;
		virtual	void			insert_slot(OI_number,OI_lm_box*,OI_lm_glue* =NULL,OI_lm_glue* =NULL) ;
		virtual	OI_number		minimum_size_x() const ;
		virtual	OI_number		minimum_size_y() const ;
		virtual	void			new_default_space() ;
		virtual	OI_lm_box		*next_box(const OI_layout_slot*) const ;
		virtual	OI_number		nominal_size_x() const ;
		virtual	OI_number		nominal_size_y() const ;
			OI_number		num_boxes() const ;
		virtual	long			origin_x() const ;
		virtual	long			origin_y() const ;
		virtual	OI_number		position() const ;
		virtual	void			position_slots() ;					/* position slots within the layout */
		virtual	OI_lm_box		*prev_box(const OI_layout_slot*) const ;
		virtual	void			set_origin(long x, long y) ;
			void			set_position(OI_number v)		{ val=v; }
			void			set_slot(OI_layout_slot *sp)		{ slotp=sp; }
		virtual	void			set_size(OI_number w, OI_number h) ;
			void			set_stretch(OI_number w, OI_number h)	{ strtch.x=w; strtch.y=h; }
			void			shift_down() ;
			void			shift_up() ;
		virtual	OI_number		size_x() const ;
		virtual	OI_number		size_y() const ;
			OI_layout_slot		*slot() const				{ return(slotp); }
		virtual	OI_number		stretch_x() const ;
		virtual	OI_number		stretch_y() const ;
		virtual	void			unlink() ;
		} ;

		class	OI_lm_obj_box : public OI_lm_box {					/* slot for object in row/col based layout */
			OI_d_tech		*objp;							/* pointer to object */
		 protected:
		 public:
						OI_lm_obj_box(OI_d_tech*,OI_layout_method*) ;
		virtual				~OI_lm_obj_box();
			void			assume_nominal_size(OI_number*,OI_number*) ;		/* set nominal size based on object size */
		virtual	OI_gravity		gravity() const ;
		virtual	void			minimum_size(OI_number*,OI_number*) const ;
		virtual	OI_number		nominal_inslot_height() const ;
		virtual	OI_number		nominal_inslot_width() const ;
		virtual	void			nominal_size(OI_number*,OI_number*) const ;
		virtual	OI_d_tech		*object() const ;
		virtual	OI_number		obj_offset_x() const ;					/* offset of object from OI_lm_obj_box origin */
		virtual	OI_number		obj_offset_y() const ;
			void			set_object(OI_d_tech *p)	{ objp=p; }
		virtual	void			set_origin(long, long) ;
		virtual	void			set_size(OI_number, OI_number) ;
		virtual	OI_number		stretch_x() const ;
		virtual	OI_number		stretch_y() const ;
		virtual	void			unlink() ;
		} ;

 /* layout geometry object used when converting between layout methods */
#define		OI_LM_FREE_P1			0x1		/* 1 => p1 must be free'd when object is destroyed */
#define		OI_LM_FREE_P2			0x2		/* 1 => p2 must be free'd when object is destroyed */
#define		OI_LM_XY			0x4		/* 1 => p1, p2 are x,y positions */

		class	OI_lm_convert_geometry	{		/* layout geometry info */
			OI_lm_convert_geometry	*nxtp ;		/* ptr to next geometry spec */
			OI_d_tech		*objp ;		/* ptr to object in layout being converted */
		union				{
			void			*gsp ;		/* geometry spec a OI_layout_geometry_spec* */
			void			*v ;		/* geometry spec as a void* */
			long			l ;		/* geometry spec as a long (for backward compatibility) */
		}	p1,p2 ;					/* geometry specs */
			unsigned long		ctl_bits ;	/* control bits */
		 public:
						OI_lm_convert_geometry(OI_d_tech*,void*,OI_bool,void*,OI_bool) ;
//						OI_lm_convert_geometry(OI_d_tech*,OI_layout_geometry_spec*) ;
//						OI_lm_convert_geometry(OI_d_tech*,void*,void*) ;
						OI_lm_convert_geometry(OI_d_tech*,long,long) ;
						~OI_lm_convert_geometry() ;
			void			*geometry_1() const		{ return(p1.v); }
			void			*geometry_2() const		{ return(p2.v); }
			OI_bool			is_xy() const			{ return((ctl_bits & OI_LM_XY) ? OI_yes : OI_no); }
			OI_lm_convert_geometry	*next() const			{ return(nxtp); }
			OI_d_tech		*object() const			{ return(objp); }
			void			set_next(OI_lm_convert_geometry *p)	{ nxtp=p; }
			long			x() const			{ return(p1.l); }
			long			y() const			{ return(p2.l); }
		} ;

 /* OI_layout_method private control bits */
#define		OI_LM_AUTO_RESIZE		0x1							/* 1 => do auto resize on add/remove */
#define		OI_LM_NEEDS_SIZE_ADJUST		0x2							/* 1 => needs size adjust due to child change */
#define		OI_LM_GAPS			0x4							/* 1 => allows gaps in numbering sequence */
#define		OI_LM_NOM_SIZ_OK		0x8							/* 1 => nom contains previously computed nominal size */

		class	OI_layout_method : public OI_lm_obj_box {					/* generic layout method */
			unsigned long		ctl_bits ;						/* object private control bits */
			OI_number		layout_ctr ;						/* > 0 => layout in process */
			OI_number		hz_sp,vt_sp ;						/* extra space around layout method */
			OI_xy			nom ;							/* nominal size, saved for optimization; */
		 public:
		static	OI_class		*clsp ;							/* ptr to class object for this layout method */
		 protected:
		virtual	OI_layout_method	*layout_method() const ;
			OI_bool			needs_size_adjust() const ;
			OI_number		nom_size_x() const		{ return(nom.x); }	// only good if nominal_size_ok
			OI_number		nom_size_y() const		{ return(nom.y); }	// only good if nominal_size_ok
			OI_bool			nominal_size_ok() const ;
			void			set_needs_size_adjust() ;
			void			set_nominal_size_ok(OI_number,OI_number) ;
		 public:
		//-------------------------------------------------------------------------------------------------		
		//		
		//	RESTRICTED MEMBER FUNCTIONS
		//		Functions in this section are not documented in the programmer's manual and are
		//		restricted to internal use by the toolkit.
		//		Functions not contained in user documentation are subject to change without notice
		//		and should never be used by toolkit users.
		//		Please maintain alphabetical order to facilitate releases and documentation.
		//
		//-------------------------------------------------------------------------------------------------		
						OI_layout_method(OI_d_tech *dtp) ;
		virtual				~OI_layout_method() ;
			void			clear_needs_size_adjust() ;
			void			clear_nominal_size_ok() ;
			OI_number		layout_count() const		{ return(layout_ctr); }
		virtual	void			nominal_size(OI_number*,OI_number*) const = 0 ;
		virtual	void			set_size(OI_number w, OI_number h) ;
		virtual	void			*redirect_0(void*, void*, void*, void*, void*, void*);
		virtual	void			*redirect_1(void*, void*, void*, void*, void*, void*);
		virtual	void			*redirect_2(void*, void*, void*, void*, void*, void*);
		virtual	void			*redirect_3(void*, void*, void*, void*, void*, void*);
		virtual	void			*redirect_4(void*, void*, void*, void*, void*, void*);

		//-------------------------------------------------------------------------------------------------		
		//		
		//	OBSOLETE MEMBER FUNCTIONS	
		//		Functions in this section were have been marked as obsolete.
		//		They are obsolete because they assume a row-column based layout method,
		//		which is overly restrictive.  They should not be used without insuring
		//		that the layout method being used is derived from OI_layout_row_col (OI_lm_row_col)
		//
		//-------------------------------------------------------------------------------------------------		
			void			allow_auto_resize() ;
			void			disallow_auto_resize() ;
			OI_bool			is_auto_resize() const ;

		//-------------------------------------------------------------------------------------------------		
		//	DOCUMENTED MEMBER FUNCTIONS needed only when deriving a new layout method
		//		Functions below this point are documented in the programmers manual, and define the interface
		//		available to users for deriving their own layout methods.
		//		Please maintain alphabetical order to facilitate releases and documentation.
		//-------------------------------------------------------------------------------------------------		
		virtual OI_number		bottom_space(OI_d_tech*) const ;
		virtual	OI_class		*class_object() const = 0 ;
			void			clear_in_layout() ;
		virtual	void			force_layout() = 0 ;				/* size parent and lay it out */
		virtual	void			gravity_change(OI_d_tech*) ;	 		/* re layout, grav chg in child object */
			OI_bool			in_layout() const ;
		virtual	void			insert(OI_d_tech*,void*,void*) = 0 ;		/* insert object in layout */
		virtual OI_number		left_space(OI_d_tech*) const ;
		virtual	void			min_outside_size(OI_number,OI_number,OI_number*,OI_number*) const = 0 ;
		virtual	void			move(OI_d_tech*,void*,void*) ;			/* move object to new layout position */
		virtual	void			new_default_space() ;				/* default spacing change */
		virtual	void			re_layout() = 0 ;				/* re layout, do the whole thing... */
		virtual	void			remove(OI_d_tech *) = 0 ;			/* remove object from the layout */
		virtual OI_number		right_space(OI_d_tech*) const ;
			void			set_in_layout()			{ layout_ctr++; }
		virtual	void			size_change() = 0 ;				/* re layout, size chg in object */
		virtual	void			slot_size_change(OI_d_tech*) = 0 ;		/* re layout, size chg in child object */
		virtual	void			space_change(OI_d_tech*) ;			/* re layout, surrounding space chg in object */
		virtual	void			size_track_change(OI_d_tech*,OI_size_track) ;	/* re layout, size track chg in child object */
		virtual OI_number		top_space(OI_d_tech*) const ;
		virtual	OI_layout		type() const = 0 ;
		//-------------------------------------------------------------------------------------------------		
		//	DOCUMENTED MEMBER FUNCTIONS	
		//		Functions below this point are documented in the programmers manual for use by normal user programs
		//		Please maintain alphabetical order to facilitate releases and documentation.
		//-------------------------------------------------------------------------------------------------		
			void			allow_gaps() ;
			virtual	OI_lm_convert_geometry	*conversion_specifications(const OI_layout_method*) const /* = 0 g++ gens bad code*/ ;
		virtual	void			convert_xy_to_geometry(OI_d_tech*,long,long,OI_number,void**,OI_bool*,void**,OI_bool*) const = 0 ;
			void			disallow_gaps() ;
		virtual	OI_bool			exact_conversion(OI_class*) const = 0 ;		/* can this method convert geometry from another exactly? */
			OI_bool			exact_conversion(OI_layout_method*) const ;
			OI_bool			gaps() const ;
		virtual	OI_bool			geometry(OI_d_tech*,void**,OI_bool*,void**,OI_bool*) const = 0 ;	/* get layout geometry */
		virtual	OI_bool			geometry_match(OI_d_tech*,void*,void*) const = 0 ;	/* chk layout geometry */
		virtual	char*			geometry_to_string(OI_d_tech*) const = 0 ;		/* convert position to string */
			OI_number		horz_offset() const		{ return(hz_sp); }
			OI_bool			is_derived_from(const char*) const ;		/* check class derivation */
			OI_bool			is_derived_from(XrmQuark) const ;
			OI_bool			is_derived_from(OI_class*) const ;
		virtual	OI_d_tech		*next_object(OI_d_tech*) const = 0 ;		/* get next object in "normal" order */
		virtual	OI_bool			overlaps_children() const ;			/* OI_YES => laid out children may overlap */
		virtual	OI_d_tech		*previous_object(OI_d_tech*) const ;		/* get previous object in "normal" order */
			void			set_space(OI_number,OI_number=OI_undefined) ;		/* set space around layout method */
		virtual	OI_bool			string_to_geometry(const char*,void**,OI_bool*,void**,OI_bool*) const = 0 ;	/* get slot layout geometry */
			OI_number		vert_offset() const			{ return(vt_sp); }
		} ;

/***************************************************************************************
 *	OI_layout_geometry_spec
 *	OI_layout_geometry_spec is a virtual base class whose sole purpose is to provide
 *	virtual destructors for geometry specifications
 *	When a geometry spec can fit in a cast to a void*, as is the case for all the
 *	supplied layout methods, there is no need for an OI_layout_geometry_spec
 *	However, if a user-derived layout_method requires a geometry specification which
 *	will not fit in a void*, it should be derived from OI_layout_geometry_spec so
 *	that when the del_p1 and del_p2 parameters in geometry calls are set OI_yes,
 *	the spec can be properly deleted.
 ***************************************************************************************/
		class	OI_layout_geometry_spec {	// Virtual base class for geometry specifications
		//-------------------------------------------------------------------------------------------------		
		//	DOCUMENTED MEMBER FUNCTIONS	
		//		Functions below this point are documented in the programmers manual for use by normal user programs
		//		Please maintain alphabetical order to facilitate releases and documentation.
		//-------------------------------------------------------------------------------------------------		
		protected:
						OI_layout_geometry_spec() ;
		public:
		virtual				~OI_layout_geometry_spec() ;
		} ;

#endif /* OI_layout_H */
