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

#include "GLUTVertPane.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;
#endif

GLUTVertPane::GLUTVertPane(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
	{ // GLUTVertPane()															//	constructor
	alignment = Alignment;														//	store the alignment policy
	} // GLUTVertPane()

void GLUTVertPane::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 vertSpaceAvailable;														//	space to be divided among stretchy panes	
	int spacePerStretchyPane;													//	how much space per stretchy pane
	int bottomEdge;															//	bottom edge of a given pane

#ifdef DEBUG_LAYOUT
	for (int i = 0; i < paneDepth; i++) printf("|");
	printf("Entering GLUTVertPane::Reshape() for %s with %d x %d (%d x %d)\n", name, Width, Height, 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->growVert)													//	if the child is allowed to grow vertically
			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
			vertSpaceRequired += child->height;									//	add the child's height to the space required
			} // fixed-size child
		if (!child->growHoriz)													//	if the child is fixed horizontally
			if (child->width > horizSpaceRequired) horizSpaceRequired = child->width;		//	take the max. of child widths
		} // 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
	
	vertSpaceAvailable = Height - vertSpaceRequired;									//	compute how much spare space there is
	if (nStretchy > 0)	spacePerStretchyPane = vertSpaceAvailable / nStretchy;				//	compute the amount of space per stretchy pane
	else	spacePerStretchyPane = 0;												//	be paranoid
	bottomEdge = bottom;														//	start at bottom
		
	for (whichChild = nChildren - 1; whichChild >= 0; 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("Bottom edge now %d, vertSpaceAvailable = %d\n", bottomEdge, vertSpaceAvailable);
#endif

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

		child->Reshape(childWidth, childHeight);									//	ask the child to reshape accordingly
		bottomEdge += childHeight;												//	update the bottom 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 GLUTVertPane::Reshape() for %s with %d x %d (%d x %d)\n", name, Width, Height, width, height);
#endif
	} // Reshape()

GLUTVertWhitePane::GLUTVertWhitePane(const char *Name, GLUTPane *Parent, int Width, int Height, bool GrowHoriz, bool GrowVert,	
	int Alignment)																//	constructor
	: GLUTVertPane(Name, Parent, Width, Height, GrowHoriz, GrowVert, Alignment)
	{ // GLUTVertWhitePane()
	} // GLUTVertWhitePane()
	
void GLUTVertWhitePane::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 GLUTVertPane::PrintType()													//	prints text string for type
	{ // PrintType()
	printf("GLUTVertPane");
	} // PrintType()	

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