/////////////////////////////////////////////////////////////////////////////
// Name:        No names yet.
// Purpose:     Contrib. demo
// Author:      Aleksandras Gluchovas
// Modified by:
// Created:     3/01/99
// RCS-ID:      $Id: nbookglyph.cpp,v 1.8 2001/02/25 12:01:18 aleksandras Exp $
// Copyright:   (c) Aleksandras Gluchovas
// Licence:   	wxWindows license
/////////////////////////////////////////////////////////////////////////////
 
#ifdef __GNUG__
#pragma implementation "objstore.h"
// #pragma interface
#endif

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include "wx/pmf/pm_undef.h"

#include "nbookglyph.h"

/***** Implemntation for class NotebookNode *****/

IMPLEMENT_DYNAMIC_CLASS( NotebookNode, MultiFaceNodeBase )

NotebookNode::NotebookNode()
{}

NotebookNode::~NotebookNode()
{}

wxDMNode* NotebookNode::Clone( bool uniqueCopy, bool cloneChildren )
{
	NotebookNode* pCopy = new NotebookNode();

	AssignData( pCopy, uniqueCopy, cloneChildren );

	return pCopy;
}

void NotebookNode::OnChildInserted( wxDMNode* pNode )
{
	MultiFaceNodeBase::OnChildInserted( pNode );

	/*
	WidgetGlyph* pGlyph = mpView->FindGlyphForNode( *this );

	if ( pGlyph )
	{
		XRect lbounds = this->GetLimitingBounds();
		lbounds.x = lbounds.y = 0;

		((WidgetNode*)pNode)->SetBounds( lbounds, pGlyph->GetCanvas() );

		((NotebookGlyph*)pGlyph)->SetVisibleFace( this->GetChildCount() - 1 );
	}
	*/
}

/***** Implemntation for class NotebookGlyph *****/

IMPLEMENT_DYNAMIC_CLASS( NotebookGlyph, MultiFaceGlyphBase )

NotebookGlyph::NotebookGlyph()

	: mTabRowHeight( 0 )
{}

NotebookGlyph::~NotebookGlyph()
{
	WX_CLEAR_ARRAY( mPageInfos );
}

void NotebookGlyph::SetBounds( const XRect& bounds )
{
	WidgetGlyph::SetBounds( bounds );

	RecalcFaceGeometry( GetCanvas() );
}

void NotebookGlyph::SetBoundsSilent( const XRect& bounds )
{
	WidgetGlyph::SetBoundsSilent( bounds );

	RecalcFaceGeometry( GetCanvas() );
}

bool NotebookGlyph::OnMouseDown ( const XPoint& pos )
{
	for( size_t i = 0; i != mPageInfos.Count(); ++i )

		if ( mPageInfos[i]->mTabBounds.Contains( pos ) )
		{
			SetVisibleFace( i ); // handled by MultiFaceGlyphBase class

			return TRUE;
		}

	return FALSE; // event not handled
}

// FIXME:: hardcoded?
#define TAB_INSET_X  5
#define TAB_INSET_Y  5
#define PAGE_INSET_X 5
#define PAGE_INSET_Y 5

void NotebookGlyph::Draw( wxDC& canvas )
{
	if ( !mpBmp )

		RegenerateLookBitmap();

	if ( mPageInfos.Count() != mpNode->GetChildCount() )

		RecalcFaceGeometry( canvas );
#if 1
	// DBG::
	wxBrush bkbr( wxColour(192,192,192), wxSOLID );
	canvas.SetBrush( bkbr );
	canvas.SetPen( *wxTRANSPARENT_PEN );

	canvas.DrawRectangle( mPixBounds.x, mPixBounds.y, mPixBounds.width, 
						  mActivePageBounds.y - mPixBounds.y );
#endif

	int y = mActivePageBounds.y - PAGE_INSET_Y;
	int x = mPixBounds.x;
	int width = mPixBounds.width;
	int height = mPixBounds.height - ( y - mPixBounds.y );

	if ( mPageInfos.Count() == 0 )
	{
		x = mPixBounds.x;
		y = mPixBounds.y;
		width = mPixBounds.width;
		height = mPixBounds.height;
	}

	// left-edge
	canvas.SetPen( *wxWHITE_PEN );
	canvas.DrawLine( x, y, x, y + height );
	canvas.SetPen( *wxLIGHT_GREY_PEN );
	canvas.DrawLine( x+1, y, x+1, y + height );

	// bottom-edge
	canvas.SetPen( *wxBLACK_PEN );
	canvas.DrawLine( x, y + height - 1, x + width, y + height - 1 );
	canvas.SetPen( *wxGREY_PEN );
	canvas.DrawLine( x + 1, y + height - 2, x + width, y + height - 2 );

	// right-edge
	canvas.SetPen( *wxBLACK_PEN );
	canvas.DrawLine( x + width - 1, y, x + width - 1, y + height );
	canvas.SetPen( *wxGREY_PEN );
	canvas.DrawLine( x + width - 2, y, x + width - 2, y + height );

	// draw all inactive tabs first

	canvas.SetTextForeground( *wxBLACK );

	for( size_t i = 0; i != mPageInfos.Count(); ++i )
	
		if ( i != GetVisibleFace() )

			DrawTab( *mPageInfos[i], canvas, FALSE );
	
	if ( GetVisibleFace() < mPageInfos.Count() )

		DrawTab( *mPageInfos[ GetVisibleFace() ], canvas, TRUE );

	// top-edge

	if ( mPageInfos.Count() )
	{
		// edge-line is split by active-tab

		NotebookPageInfo& active = *mPageInfos[ GetVisibleFace() ];

		canvas.SetPen( *wxWHITE_PEN );
		canvas.DrawLine( x, y - 1, active.mTabBounds.x - 4, y - 1);
		canvas.DrawLine( active.mTabBounds.x + active.mTabBounds.width + 4, 
						 y - 1, x + width, y - 1 );
	}
	else
	{
		canvas.SetPen( *wxWHITE_PEN );
		canvas.DrawLine( x, y, x + width, y );
	}
}

/*** protected methods ***/

void NotebookGlyph::DrawTab( NotebookPageInfo& tab, wxDC& dc, bool isActive )
{
	int x = tab.mTabBounds.x;
	int y = tab.mTabBounds.y;
	int width  = tab.mTabBounds.width;
	int height = tab.mTabBounds.height;

	if ( !isActive )
	{
		y += 2;
		height -= 2;
	}
	else
	{
		x     -= 4;
		width += 8;
	}

	dc.SetPen( *wxWHITE_PEN );

	dc.DrawLine( x,y+2, x+2,y );
	dc.DrawLine( x+2, y, x + width - 2, y );
	dc.DrawLine( x, y+3, x, y + height );

	dc.SetPen( *wxLIGHT_GREY_PEN );
	dc.DrawLine( x+1, y + 2, x+1, y + height - 1 );

	dc.SetPen( *wxGREY_PEN );
	dc.DrawLine( x + width - 2, y + 1, x + width - 2, y + height );
	dc.SetPen( *wxBLACK_PEN );
	dc.DrawLine( x + width - 1, y + 2, x + width - 1, y + height );

	if ( isActive )
	{
		// FIXME:: use system-background color

		dc.SetPen( *wxLIGHT_GREY_PEN );
		dc.DrawLine( x+2, y + 2, x+2, y + height );
		dc.DrawLine( x+3, y + 1, x+3, y + height );
		dc.DrawLine( x + width - 3, y + 2, x + width - 3, y + height );
		dc.DrawLine( x + width - 4, y + 1, x + width - 4, y + height );
	}

	dc.DrawText( tab.mLabel, tab.mLabelPos.x, 
				 tab.mLabelPos.y - ( isActive ? 2: 0 ) );

	if ( tab.mImage.Ok() )
	
		dc.DrawBitmap( tab.mImage, tab.mImagePos.x, 
					   tab.mImagePos.y );
}

void NotebookGlyph::RecalcFaceGeometry( wxDC& dc )
{
	WX_CLEAR_ARRAY( mPageInfos );

	int tabRowWidth  = 0;
	mTabRowHeight = 0;

	int maxWidth = 0;

	if ( mVisibleFace >= mpNode->GetChildCount() )

		mVisibleFace = 0;

	size_t i = 0;
	for( ; i != mpNode->GetChildCount(); ++i )
	{
		WidgetNode& child = *(WidgetNode*)mpNode->GetChild(i);

		NotebookPageInfo* pInfo = new NotebookPageInfo();

		pInfo->mLabel = child.GetNodeExtraAttrValue( "label" );
		wxString imgFile = child.GetNodeExtraAttrValue( "image" );
		pInfo->mImage = wxPMBmpMgr().FindBitmapByFileName( imgFile );

		if ( pInfo->mImage == wxPMBmpMgr().GetWrongBitmap() )

			pInfo->mImage = wxBitmap();

		// first, calculate relative positions of image and label

		int w = 0, h = 0;

		if ( pInfo->mImage.Ok() )
		{
			pInfo->mImagePos.x = 4; // left-margin
			pInfo->mImagePos.y = 0;

			w = pInfo->mImage.GetWidth() + pInfo->mImagePos.x;
			h = pInfo->mImage.GetHeight();
		}

		if ( pInfo->mLabel.Length() )
		{
			long tw = 0, th = 0;

			dc.GetTextExtent( pInfo->mLabel, &tw, &th );

			pInfo->mLabelPos.y = w;

			if ( pInfo->mImage.Ok() )
			{			
				w += 10; // text-to-image gap
				pInfo->mLabelPos.x = w;

				w += tw;

				// center both image and label vertically
				h = wxMax( h, th );
				pInfo->mLabelPos.y = ( h - th ) / 2;
				pInfo->mImagePos.y = ( h - pInfo->mImage.GetHeight() ) / 2;
			}
			else
			{
				pInfo->mImagePos  = XPoint(4, // left margin
										   0);
				w = tw; h = th;
			}
		}

		pInfo->mTabBounds.width  = w;
		pInfo->mTabBounds.height = h;

		mTabRowHeight = wxMax( mTabRowHeight, h );

		maxWidth = wxMax( maxWidth, w );

		mPageInfos.Add( pInfo );
	}

	// now calculate absolute positions of each tab-item

	mTabRowHeight += TAB_INSET_Y*2;

	// FIXME:: better way to cope with char-height dependent parameters
	this->GetLookInfo()->mEdges[TOP_LOOK_EDGE].mInset = mTabRowHeight;

	int x = mPixBounds.x + 4;
	int y = mPixBounds.y;

	if ( ( maxWidth + TAB_INSET_X*4 ) * mPageInfos.Count() >= (unsigned int)mPixBounds.width )

		maxWidth = -1; // mark that heading-space should is sparse

	for( i = 0; i != mPageInfos.Count(); ++i )
	{
		NotebookPageInfo& info = *mPageInfos[i];

		info.mTabBounds.x = x;
		info.mTabBounds.y = y;

		if ( maxWidth == -1 ) // heading-space economy?

			info.mTabBounds.width += TAB_INSET_X*4;
		else
			info.mTabBounds.width = maxWidth + TAB_INSET_X*4;

		info.mTabBounds.height = mTabRowHeight;

		info.mImagePos.x += x + TAB_INSET_X * 2;
		info.mImagePos.y += y + TAB_INSET_Y;
		info.mLabelPos.x += x + TAB_INSET_X * 2;
		info.mLabelPos.y += y + TAB_INSET_Y + 1;

		x += info.mTabBounds.width;
		tabRowWidth += info.mTabBounds.width;
	}

	mActivePageBounds.x = mPixBounds.x + PAGE_INSET_X;
	mActivePageBounds.y = mPixBounds.y + PAGE_INSET_Y + mTabRowHeight;

	mActivePageBounds.width  = mPixBounds.width  - PAGE_INSET_X*2;
	mActivePageBounds.height = mPixBounds.height - PAGE_INSET_Y*2 - mTabRowHeight;
}