/******************************************************************************
 JXCardFile.cc

	System independent base class for a set of equally sized cards, only one
	of which can be displayed at a time.  Essentially, this acts like a
	stack of 3x5 cards that one holds in one's hand.

	Derived classes are responsible for providing a way to switch between
	cards.  Examples are menus, tables, or a row of tabs across the top or
	along the side.

	BASE CLASS = JXWidgetSet

	Copyright © 1997 by John Lindal. All rights reserved.

 ******************************************************************************/

#include <JXCardFile.h>
#include <JXWindow.h>
#include <jAssert.h>

/******************************************************************************
 Constructor

 ******************************************************************************/

JXCardFile::JXCardFile
	(
	JXContainer*		enclosure,
	const HSizingOption	hSizing,
	const VSizingOption	vSizing,
	const JCoordinate	x,
	const JCoordinate	y,
	const JCoordinate	w,
	const JCoordinate	h
	)
	:
	JXWidgetSet(enclosure, hSizing, vSizing, x,y, w,h)
{
	itsCards = new JPtrArray<JXContainer>;
	assert( itsCards != NULL );

	itsCurrCardIndex = 0;
}

/******************************************************************************
 Destructor

 ******************************************************************************/

JXCardFile::~JXCardFile()
{
	delete itsCards;	// objects owned by JXContainer
}

/******************************************************************************
 InsertCard

	The first version creates a new card, inserts it at the specified index,
	and returns it.

	The second version lets you provide the card, so that you can use
	a derived class to add intelligence.  The card's enclosure must be
	the JXCardFile.  We own the card after you give it to us.

 ******************************************************************************/

JXWidgetSet*
JXCardFile::InsertCard
	(
	const JIndex index
	)
{
	JXWidgetSet* card = new JXWidgetSet(this, kHElastic, kVElastic, 0,0, 10,10);
	assert( card != NULL );
	InsertCard(index, card);
	return card;
}

void
JXCardFile::InsertCard
	(
	const JIndex index,
	JXWidgetSet* card
	)
{
	assert( const_cast<JXContainer*>(card->GetEnclosure()) == this );

	card->SetSizing(kHElastic, kVElastic);
	card->FitToEnclosure();
	card->Hide();

	itsCards->InsertAtIndex(index, card);
	if (index <= itsCurrCardIndex)
		{
		itsCurrCardIndex++;
		}
}

/******************************************************************************
 RemoveCard

	Removes the specified card and returns a pointer to it so you can
	keep track of it.

	*** You are not allowed to remove the currently visible card.

 ******************************************************************************/

JXWidgetSet*
JXCardFile::RemoveCard
	(
	const JIndex index
	)
{
	assert( index != itsCurrCardIndex);

	JXWidgetSet* card = dynamic_cast(JXWidgetSet*, itsCards->NthElement(index));
	assert( card != NULL );

	itsCards->RemoveElement(index);
	if (index < itsCurrCardIndex)
		{
		itsCurrCardIndex--;
		}

	return card;
}

/******************************************************************************
 DeleteCard

	Deletes the specified card and everything on it.

	*** You are not allowed to delete the currently visible card.

 ******************************************************************************/

void
JXCardFile::DeleteCard
	(
	const JIndex index
	)
{
	assert( index != itsCurrCardIndex);

	itsCards->DeleteElement(index);
	if (index < itsCurrCardIndex)
		{
		itsCurrCardIndex--;
		}
}

/******************************************************************************
 KillFocusOnCurrentCard

	If one of the widgets on the current card has focus, we call KillFocus().
	This is useful when you want to discard the current card without saving
	its contents.

 ******************************************************************************/

void
JXCardFile::KillFocusOnCurrentCard()
{
	if (itsCurrCardIndex > 0)
		{
		JXWindow* window      = GetWindow();
		JXContainer* currCard = itsCards->NthElement(itsCurrCardIndex);

		JXWidget* widget;
		if (window->GetFocusWidget(&widget) &&
			currCard->IsAncestor(widget))
			{
			window->KillFocus();
			}
		}
}

/******************************************************************************
 ShowCard

	If the current card is willing to disappear, then we show the requested
	one and return kTrue.  Otherwise, we return kFalse.

 ******************************************************************************/

JBoolean
JXCardFile::ShowCard
	(
	JXWidgetSet* card
	)
{
	JIndex index;
	if (itsCards->Find(card, &index))
		{
		return ShowCard(index);
		}
	else
		{
		return kFalse;
		}
}

JBoolean
JXCardFile::ShowCard
	(
	const JIndex index
	)
{
	if (itsCurrCardIndex == index)
		{
		return kTrue;
		}

	JXWindow* window = GetWindow();

	// If a card is visible and a widget on this card has focus,
	// then make sure that it is willing to give up focus.

	JBoolean hadFocus = kFalse;
	if (itsCurrCardIndex > 0)
		{
		JXContainer* currCard = itsCards->NthElement(itsCurrCardIndex);

		JXWidget* widget;
		if (window->GetFocusWidget(&widget) &&
			currCard->IsAncestor(widget))
			{
			if (widget->OKToUnfocus())
				{
				hadFocus = kTrue;
				}
			else
				{
				return kFalse;
				}
			}

		currCard->Hide();
		}

	// Show the requested card and focus to the first widget on it.

	itsCurrCardIndex      = index;
	JXContainer* currCard = itsCards->NthElement(itsCurrCardIndex);

	currCard->Show();
	if (hadFocus)
		{
		window->SwitchFocusToFirstWidgetWithAncestor(currCard);
		}

	return kTrue;
}
