///////////////////////////////////////////////////
//
//	Contour-tree based isosurfaces
//	version 3.0
//	copyright Hamish Carr
//	February, 2001
//
//	------------------------
//	GLUTHorizPane.cpp
//	------------------------
//	
//	A pane that stacks subpanes horizontally
//
//	Notes:
//	------
//
//
//	Change log:
//	-----------
//	Date:		Changes:
//	-----		--------
//	02/07/01		Initial version
//
///////////////////////////////////////////////////	

#include "GLUTHorizPane.h"														//	the header
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <stdlib.h>																//	needed for NULL, of all things
#include <stdio.h>																//	C I/O

#ifdef DEBUG_LAYOUT
extern int paneDepth;															//	in GLUTVertPane.cpp
#endif

GLUTHorizPane::GLUTHorizPane(const char *Name, GLUTPane *Parent, int Width, int Height, bool GrowHoriz, bool GrowVert, int Alignment)
	: GLUTPane(Name, Parent, Width, Height, GrowHoriz, GrowVert)								//	call inherited constructor
	{ // GLUTHorizPane()														//	constructor
	alignment = Alignment;														//	set alignment
	} // GLUTHorizPane()

void GLUTHorizPane::Reshape(int Width, int Height)									//	window reshape routine
	{ // Reshape()
	int nFixed = 0, nStretchy = 0;												//	counters for the different types of children
	int horizSpaceRequired = 0;													//	horizontal space required by fixed children
	int vertSpaceRequired = 0;													//	how much vertical space is required
	int whichChild;															//	loop index
	GLUTPane *child;															//	local pointer to a child
	int horizSpaceAvailable;														//	space to be divided among stretchy panes	
	int spacePerStretchyPane;													//	how much space per stretchy pane
	int leftEdge;																//	left-hand edge of a given pane

#ifdef DEBUG_LAYOUT
	for (int i = 0; i < paneDepth; i++) printf("|");
	printf("Entering GLUTHorizPane::Reshape() for %s with %d x %d\n", name, Width, Height);
	paneDepth++;
#endif

	for (whichChild = 0; whichChild < nChildren; whichChild++)							//	loop through child panes
		{ // loop through child panes
		child = children[whichChild];												//	grab a pointer to the child
#ifdef DEBUG_LAYOUT
		for (int i = 0; i < paneDepth; i++) printf("|");
		printf("Child %d (%s: ", whichChild, child->name); child->PrintType(); printf(") of %d is %d wide x %d high and is %s vertically and %s horizontally\n", 
			nChildren, child->width, child->height, child->growVert ? "stretchy": "fixed",
			child->growHoriz ? "stretchy" : "fixed");
#endif
		if (child->growHoriz)													//	if the child is allowed to grow horizontally
			nStretchy++;														//	then add one to the number of stretchy children
		else																	//	i.e. fixed size
			{ // fixed-size child
			nFixed++;															//	add one to the count of fixed children
			horizSpaceRequired += child->width;									//	add the child's width to the space required
			} // fixed-size child
		if (!child->growVert)													//	if the child is fixed vertically
			if (child->height > vertSpaceRequired) 
				vertSpaceRequired = child->height;								//	take the max. of child heights
		} // loop through child panes

#ifdef DEBUG_LAYOUT
	for (int i = 0; i < paneDepth; i++) printf("|");
	printf("Space required (w,h): %d, %d\n", horizSpaceRequired, vertSpaceRequired);
#endif
	
	if (horizSpaceRequired > Width)												//	if this happens, we have a problem
		Width = horizSpaceRequired;												//	so reset it: eventually, the window will notice

	if (vertSpaceRequired > Height)												//	if this happens, we also have a problem
		Height = vertSpaceRequired;												//	again, assume the window will eventually notice

	if ((!growHoriz) & (width > horizSpaceRequired))									//	if the pane itself needs more room
		Width = width;															//	use this as the minimum

	if ((!growVert) & (height > vertSpaceRequired))									//	if the pane itself needs more room
		Height = height;														//	use this as the minimum

	width = Width; height = Height;												//	reset the pane's width and height	

#ifdef DEBUG_LAYOUT
	for (int i = 0; i < paneDepth; i++) printf("|");
	printf("Size (w,h): %d, %d\n", width, height);
#endif
		
	horizSpaceAvailable = Width - horizSpaceRequired;									//	compute how much spare space there is
	if (nStretchy > 0)	spacePerStretchyPane = horizSpaceAvailable / nStretchy;			//	compute the amount of space per stretchy pane
	else	spacePerStretchyPane = 0;												//	be paranoid
	leftEdge = left;															//	start at left
		
	for (whichChild = 0; whichChild < nChildren; whichChild++)							//	loop through child panes
		{ // loop through child panes
		int childWidth, childHeight;												//	new width & height for the child
		child = children[whichChild];												//	grab a pointer to the child

#ifdef DEBUG_LAYOUT
		for (int i = 0; i < paneDepth; i++) printf("|");
		printf("Left edge now %d, horizSpaceAvailable = %d\n", leftEdge, horizSpaceAvailable);
#endif

		child->left = leftEdge;													//	set the new left edge of the child
		if (child->growHoriz)													//	if the child is allowed to grow horizontally
			{ // a stretchy pane
			if (nStretchy-- == 1)												//	if this is the last stretchy child
				spacePerStretchyPane = horizSpaceAvailable;							//	make sure it get any spare pixels	
			childWidth = spacePerStretchyPane;										//	set the width
			horizSpaceAvailable -= childWidth;										//	and update the available space
			} // a stretchy pane
		else																	//	i.e. fixed size
			{ // fixed-size child
			childWidth = child->width;											//	set the width
			} // fixed-size child
		if (child->growVert)													//	if the child grows vertically
			{ // stretchy vertically
			child->bottom = bottom;												//	set it to the same bottom as this pane
			childHeight = Height;												//	and set the height
			} // stretchy vertically
		else // i.e. fixed vertically
			{ // fixed vertically
			switch (alignment)													//	depending on the pane's alignment policy
				{ // switch on alignment
				case ALIGN_VERTICAL_BOTTOM:										//	sticking to bottom edge
					child->bottom = bottom;
					break;
				case ALIGN_VERTICAL_TOP:											//	sticking to top edge
					child->bottom = bottom + Height - child->height;	
					break;
				case ALIGN_VERTICAL_CENTRE:										//	vertically centred
				default:														//	and (from paranoia), anything else
					child->bottom = bottom + (Height - child->height)/2;	
					break;
				} // switch on alignment
			childHeight = child->height;											//	retrieve the child's height
			} // fixed vertically

		child->Reshape(childWidth, childHeight);									//	ask the child to reshape accordingly
		leftEdge += childWidth;													//	update the left edge position

#ifdef DEBUG_LAYOUT
		for (int i = 0; i < paneDepth; i++) printf("|");
		printf("Child %d (%s: ", whichChild, child->name); 
		child->PrintType();
		printf(") now has position %d %d, size %d x %d\n", child->left, child->bottom, child->width, child->height);
#endif

		} // loop through child panes

#ifdef DEBUG_LAYOUT
	paneDepth--;
	for (int i = 0; i < paneDepth; i++) printf("|");
	printf("Exiting GLUTHorizPane::Reshape() for %s with %d x %d\n", name, width, height);
#endif
	} // Reshape()
	
GLUTHorizWhitePane::GLUTHorizWhitePane(const char *Name, GLUTPane *Parent, int Width, int Height, bool GrowHoriz, bool GrowVert,	
	int Alignment)											//	constructor
	: GLUTHorizPane(Name, Parent, Width, Height, GrowHoriz, GrowVert)
	{ // GLUTHorizWhitePane()
	} // GLUTHorizWhitePane()
	
void GLUTHorizWhitePane::Display()													//	display
	{ // Display()
	GLfloat backgroundColour[3] = { 1.0, 1.0, 1.0 };									//	on white

	glPushAttrib(GL_ALL_ATTRIB_BITS);												//	save the attribute frame
	glDisable(GL_LIGHTING);														//	turn off lighting
	glDisable(GL_DEPTH_TEST);													//	turn off depth test

	glMatrixMode(GL_PROJECTION);													//	set the projection matrix
	glLoadIdentity();															//	revert to identity matrix
	glOrtho(left, left + width, bottom, bottom + height, -1.0, 1.0);						//	set projection to match viewport

	glMatrixMode(GL_MODELVIEW);													//	switch to modelview matrix
	glLoadIdentity();															//	and revert to the identity matrix
	
	glColor3fv(backgroundColour);													//	set the background colour
	//printf("Calling glBegin() level %d at %s:%d\n", ++glBeginDepth, __FILE__, __LINE__); 
	glBegin(GL_POLYGON);														//	and draw a "square"
	glVertex2f(left, bottom);
	glVertex2f(left + width, bottom);
	glVertex2f(left + width, bottom + height);
	glVertex2f(left, bottom + height);
	//printf("Calling glEnd()   level %d at %s:%d\n", glBeginDepth--, __FILE__, __LINE__);
	glEnd();

	GLUTPane::Display();														//	call the inherited version	
	glPopAttrib();																//	return to previous attributes
	} // Display()	

void GLUTHorizPane::PrintType()													//	prints text string for type
	{ // PrintType()
	printf("GLUTHorizPane");
	} // PrintType()	

void GLUTHorizWhitePane::PrintType()												//	prints text string for type
	{ // PrintType()
	printf("GLUTHorizWhitePane");
	} // PrintType()	
	
