Return to Appendix B.

TREE.CPP
// Matt Streeter
// 2/27/00
// TREE.CPP
// Implementation of class TFamilyTreeWindow; window class for display of
// network's "family tree".
// Copyright Matt Streeter, 2000.  All rights reserved

#include "tree.h"
#include "matrix.h"

DEFINE_RESPONSE_TABLE1(TFamilyTreeWindow, THeredityWindow)
  EV_WM_SIZE,
END_RESPONSE_TABLE;

// The following four #defines determine, in pixels, the left, right, top,
// and bottom borders, respectively, between window contents and the window
// edge.
#define WINDOW_LBORDER 10
#define WINDOW_RBORDER 10
#define WINDOW_TBORDER 10
#define WINDOW_BBORDER 10

// Sets the amount of vertical spacing, in pixels, between successive
// generations in the family tree.
#define GENERATION_VSPACING 20

TFamilyTreeWindow::TFamilyTreeWindow(TWindow *pParent,char *pTitle,
	TGeneration *pGenerationList,Chromosome *pSelectedNetwork,
	Network *pNetwork,double dMaxWeight,Parameter *pParam):
	THeredityWindow(pParent,pTitle,pGenerationList,pNetwork,dMaxWeight,pParam)
{
	Attr.Style|=WS_VISIBLE|WS_OVERLAPPEDWINDOW;
	// tbd: account correctly for parent coords
	Attr.X=475+(pParent?pParent->Attr.X+3:0);
	Attr.Y=200+(pParent?pParent->Attr.Y+25:0);
	Attr.W=275;
	Attr.H=325;

	mpSelectedNetwork=pSelectedNetwork;
}

void TFamilyTreeWindow::Paint(TDC& dc, bool, TRect&)
{
TRect DrawRect;

	GetClientRect(DrawRect);

	DrawRect.left+=WINDOW_LBORDER;
	DrawRect.top+=WINDOW_TBORDER;
	DrawRect.right-=WINDOW_RBORDER;
	DrawRect.bottom-=WINDOW_BBORDER;

	if(DrawRect.bottom<DrawRect.top || DrawRect.right<DrawRect.left)
		return;

	DrawTree(dc,DrawRect);
}

void TFamilyTreeWindow::EvSize(UINT SizeType, TSize& Size)
{
	TWindow::EvSize(SizeType, Size);
	if(SizeType != SIZEICONIC)
	{
		Invalidate(TRUE);
	}
}

int TFamilyTreeWindow::DrawTree(TDC& dc,TRect& DrawRect)
{
	int x=DrawRect.left+(DrawRect.right-DrawRect.left)/2;
	int iYCursor=DrawRect.bottom;
	int iWidth=DrawRect.right-DrawRect.left+1;

	for(int iDepth=0;;iDepth++)
	{
		if(iYCursor+mMatrix.GetHeight()+1<DrawRect.top)
			break;

		// determine matrix size for this layer
		long lNodes=pow(2,iDepth);
		while((long)iWidth<lNodes*mMatrix.GetWidth())
		{
			if(!mMatrix.GetPixelsPerSquare())
				break;
			mMatrix.SetPixelsPerSquare(mMatrix.GetPixelsPerSquare()-1);
		}

		if(!iDepth)
			iYCursor=DrawRect.bottom-mMatrix.GetHeight()+1;
		else
			iYCursor-=mMatrix.GetHeight()+1+GENERATION_VSPACING;
   
		DrawTreeLayer(dc,mpSelectedNetwork,x,iYCursor,iWidth,iDepth);
	}
	mMatrix.SetPixelsPerSquare(BASE_PIXELS_PER_WEIGHT);
   return(0);
}

int TFamilyTreeWindow::DrawTreeLayer(TDC& dc,Chromosome *pChromosome,
	int x,int y,int iWidth,int iDrawDepth,int iCurDepth)
{
Chromosome *pParent1,*pParent2;

	if(iCurDepth>iDrawDepth)
		return(0);

	pParent1=FindNetwork(pChromosome->miGeneration-1,
		pChromosome->miWeightParent1);
	pParent2=FindNetwork(pChromosome->miGeneration-1,
		pChromosome->miWeightParent2);

	if(pChromosome->miGeneration>0 && pChromosome->miWeightParent2==-1)
	{
		if(!pParent1)
			return(-1); // internal error
		else
			return(DrawTreeLayer(dc,pParent1,x,y,iWidth,iDrawDepth,iCurDepth));
	}

	TBrush BoxBrush(mBoxColor);
	if(iDrawDepth==iCurDepth)
	{
		dc.FrameRect(x-mMatrix.GetWidth()/2-1,y,x+mMatrix.GetWidth()/2+1,
			y+mMatrix.GetHeight()+1,BoxBrush);
		mMatrix.Paint(dc,x-mMatrix.GetWidth()/2,y+1,pChromosome);
	}

	// tbd: stop drawing if outside window

	Chromosome *pLeftParent,*pRightParent;
	if(!pParent1)
	{
		pLeftParent=pParent2;
		pRightParent=0;
	}
	else if(!pParent2)
	{
		pLeftParent=pParent1;
		pRightParent=0;
	}
	else
	{
		if(pChromosome->miWeightParent1<pChromosome->miWeightParent2)
		{
			pLeftParent=pParent1;
			pRightParent=pParent2;
		}
		else
		{
			pLeftParent=pParent2;
			pRightParent=pParent1;
		}
	}

	TPen HighlightPen(mParentHighlightColor,1);
	if(iDrawDepth==iCurDepth)
		dc.SelectObject(HighlightPen);

	if(pLeftParent)
	{
		if(iDrawDepth==iCurDepth)
		{
			dc.MoveTo(x,y-1);
			dc.LineTo(x-iWidth/4,y-GENERATION_VSPACING);
		}
		DrawTreeLayer(dc,pLeftParent,x-iWidth/4,y,iWidth/2,iDrawDepth,
			iCurDepth+1);
	}
	if(pRightParent)
	{
		if(iDrawDepth==iCurDepth)
		{
			dc.MoveTo(x,y-1);
			dc.LineTo(x+iWidth/4,y-GENERATION_VSPACING);
		}
		DrawTreeLayer(dc,pRightParent,x+iWidth/4,	y,iWidth/2,iDrawDepth,
			iCurDepth+1);
	}

	return(0);
}

Chromosome *TFamilyTreeWindow::FindNetwork(int iGeneration,int iIndex)
{
TGeneration *pCurGeneration;
int n;

	if(iGeneration<0)
		return(0);

	pCurGeneration=mpGenerationList;
	while(pCurGeneration)
	{
		for(n=0;n<pCurGeneration->iSurvivors;n++)
		{
			if(pCurGeneration->pSurvivors[n].miGeneration==iGeneration &&
				pCurGeneration->pSurvivors[n].miIndex==iIndex)
            return(&(pCurGeneration->pSurvivors[n]));
		}
		pCurGeneration=pCurGeneration->pNext;
	}
	return(0);
}

void GetFamilyTreeTitle(char *pTitle,Chromosome *pChromosome)
{
	strcpy(pTitle,"Family Tree - ");
	pChromosome->GetName(&(pTitle[strlen(pTitle)]));
}


Return to Appendix B.