/*	XGPopControl.cpp
 *
 *		Popup control
 */

/*  YAAF - Yet another application framework
 *  Copyright (C) 1997, 1998 William Edward Woody
 *  
 *  This library is free software; you can redistribute it
 *  and/or modify it under the terms of the GNU Library
 *  General Public License as published by the Free Software
 *  Foundation; either version 2 of the License, or any
 *  later version.
 *  
 *  This library is distributed in the hope that it will be
 *  useful, but WITHOUT ANY WARRANTY; without even the implied
 *  warranty of MERCHANTABIILITY or FITNESS FOR A PARTICULAR
 *  PURPOSE. See the GNU Library General Public License for
 *  more details.
 *  
 *  You should have received a copy of the GNU Library General
 *  Public License along with this library; if not, write to the
 *  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *  Boston, MA 02111-1307, USA.
 *  
 *  To contact the author, either e-mail me at woody@pandawave.com, 
 *	or write to
 *  
 *          William Edward Woody
 *          In Phase Consulting
 *          1545 Ard Eevin Avenue
 *          Glendale, CA 91202
 *
 *	Or visit us on the web at http://www.pandawave.com
 */

#include <XConfig.h>			// must be first to optimize compile on MSVC++
#include <XPopup.h>
#include <XDraw.h>
#include <XWindow.h>
#include <XDataUtil.h>
#include <XMessages.h>

/************************************************************************/
/*																		*/
/*	Popup controls														*/
/*																		*/
/************************************************************************/

/*	@F"XGPopControl::XGPopControl" @I
 *
 *		Pop up control
 */

XGPopControl::XGPopControl(XGOwner *parent, XGArgStream &stream) : XGControl(parent,stream)
{
	fFontID = stream.ReadInteger();
	fFont = XGFont::LoadFont(fFontID);
	fValue = 0;
	fPop = NULL;

#if OPT_MACOS
	ClearTabStop();
#endif
}

/*	@F"XGPopControl::~XGPopControl" @I
 *
 *		Delete me
 */

XGPopControl::~XGPopControl()
{
	if (fPop) delete fPop;
	DeleteAll();
	fFont->Detach();
}

/************************************************************************/
/*																		*/
/*	Control List Management												*/
/*																		*/
/************************************************************************/

/*	@F"XGPopControl::GetItem" @I
 *
 *		Get the specified item in a zero-based index
 */

void XGPopControl::GetItem(long index, char *data) const
{
	fList.GetString(index,data);
}

/*	@F"XGPopControl::Length" @I
 *
 *		# items in me
 */

long XGPopControl::Length() const
{
	return fList.GetNumStrings();
}

/*	@F"XGPopControl::Insert" @I
 *
 *		Insert this item
 */

void XGPopControl::Insert(long index, const char *buffer)
{
	fList.Insert(index,buffer);
	InvalView();
}

/*	@F"XGPopControl::Delete" @I
 *
 *		Delete this item
 */

void XGPopControl::Delete(long index)
{
	fList.Delete(index);
	if (fValue >= Length()) fValue = 0;
	InvalView();
}

/*	@F"XGPopControl::DeleteAll" @I
 *
 *		Delete all items
 */

void XGPopControl::DeleteAll(void)
{
	fList.DeleteAll();
	InvalView();
}

 
/************************************************************************/
/*																		*/
/*	Control List Management												*/
/*																		*/
/************************************************************************/

/*	@F"XGPopControl::GetValue" @I
 *
 *		Get the value of this thing
 */

long XGPopControl::GetValue()
{
	return fValue;
}

/*	@F"XGPopControl::SetValue" @I
 *
 *		Set the value of this thing
 */

void XGPopControl::SetValue(long value)
{
	if (value >= Length()) value = Length()-1;
	if (value < 0) value = 0;
	if (fValue == value) return;
	fValue = value;
	InvalView();
}
 
/************************************************************************/
/*																		*/
/*	Control Events														*/
/*																		*/
/************************************************************************/

/*	@F"XGPopControl::DoDrawView" @I
 *
 *		Draw the view.
 */

void XGPopControl::DoDrawView(Rect)
{
	Rect r;
	Rect s;
	XGDraw draw(this);
	fFont->Attach();
	draw.SetFont(fFont);
	
	r = GetContentRect();
	s = r;
	s.left = s.right - (s.bottom - s.top);
	::InsetRect(&s,2,2);
	
	draw.Draw3DRect(r,KXGEBackground);
	if (IsEnabled() && IsActive()) {
		draw.Draw3DRect(r,KXGEButton);
		draw.Draw3DRect(s,KXGEOutset);
	} else {
		draw.Draw3DRect(r,KXGEGrayFrame);
		draw.SetForeColor(KXGColorBtnShadow);
	}
	::InsetRect(&s,4,4);
	
	draw.MoveTo(s.left,(s.top*3+s.bottom)/4);
	draw.LineTo(s.right,(s.top*3+s.bottom)/4);
	draw.LineTo((s.left+s.right)/2,(s.top+3*s.bottom)/4);
	draw.LineTo(s.left,(s.top*3+s.bottom)/4);
	
	s = r;
	s.right -= s.bottom - s.top;
	::InsetRect(&s,1,1);
	draw.ClipRect(&s);
	
#if OPT_WINOS || OPT_XWIN
	if (HasFocus() && IsEnabled() && IsActive()) {
		::InsetRect(&s,1,1);
		draw.DrawFocusRect(s);
		::InsetRect(&s,-1,-1);
	}
#endif

	draw.MoveTo(s.left + 3,
				(s.top + s.bottom - draw.GetFontHeight())/2+draw.GetFontAscent());

	if (fValue < Length()) {
		char buffer[256];
		GetItem(fValue,buffer);
		draw.DrawString(buffer);
	}
}

/*	@F"XGPopControl::DoActivate" @I
 *
 *		Handle activate/deactivate
 */

void XGPopControl::DoActivate(bool)
{
	InvalView();
}

/*	@F"XGPopControl::DoMouseDown" @I
 *
 *		Handle mouse down event
 */

bool XGPopControl::DoMouseDown(Point,short)
{
	Rect r,s;
	Point pt;
	XGDraw draw(this);
	fFont->Attach();
	draw.SetFont(fFont);
	short nright;
	
	/*
	 *	Capture focus
	 */
	
#if OPT_WINOS || OPT_XWIN
	if (!SetFocus()) return false;
#endif
	
	/*
	 *	Draw the gadget down
	 */
	
	r = GetContentRect();
	draw.Draw3DRect(r,KXGEInButton);
	s = r;
	s.left = s.right - (s.bottom - s.top);
	::InsetRect(&s,2,2);
	draw.Draw3DRect(s,KXGEInset);
	
	/*
	 *	Pop up the list
	 */
	
	if (fPop) {
		delete fPop;
		delete fView;
		fPop = NULL;
	}
	
	fView = new XGPopMenuView(&fList,fFontID,fValue);
	r = GetContentRect();
	pt = fView->GetPopSize(draw);
	r.left++;
	r.top = r.bottom;
	r.bottom = r.top + pt.v;
	nright = r.left + pt.h;
	if (nright > r.right) r.right = nright;
	
	fPop = new XGPopWindow(this,r,fView);
	return true;
}

/*	@F"XGPopControl::DoMouseMove" @I
 *
 *		Handle mouse move event
 */

void XGPopControl::DoMouseMove(Point pt, short flag)
{
	if (fPop) {
		Rect r;
		
		r = fPop->GetLocation();
		if (PtInRect(pt,&r)) {
			pt.h -= r.left;
			pt.v -= r.top;
			fView->DoMouseMove(pt,0);
		} else {
			pt.h = -1;
			pt.v = -1;
			fView->DoMouseMove(pt,0);		// unselect kludge
		}
	} else {
		XGView::DoMouseMove(pt,flag);
	}
}

/*	@F"XGPopControl::DoMouseUp" @I
 *
 *		Handle mouse up event
 */

void XGPopControl::DoMouseUp(Point,short)
{
	Rect r,s;
	XGDraw draw(this);
	fFont->Attach();
	draw.SetFont(fFont);
	
	/*
	 *	Draw the gadget down
	 */
	
	r = GetContentRect();
	draw.Draw3DRect(r,KXGEButton);
	s = r;
	s.left = s.right - (s.bottom - s.top);
	::InsetRect(&s,2,2);
	draw.Draw3DRect(s,KXGEOutset);

	/*
	 *	Get rid of down button
	 */
	
	if (fPop) {
		short index;
		
		index = fView->GetLocation();
		if (index != -1) SetValue(index);
		delete fPop;
		fPop = NULL;
		
		DoDispatch(KXGPopValue,GetViewID(),NULL);
	}
}

/************************************************************************/
/*																		*/
/*	Keyboard navigation													*/
/*																		*/
/************************************************************************/

/*	@F"XGPopControl::GainFocus" @I
 *
 *		Gain the focus. Redraw me
 */

void XGPopControl::GainFocus()
{
	InvalView();
}

/*	@F"XGPopControl::LoseFocus" @I
 *
 *		Lose focus. Redraw me
 */

void XGPopControl::LoseFocus()
{
	InvalView();
}

BEGINDISPATCH(XGPopControl,XGControl)
	DISPATCHTABLE(KXGKeyEvent,XGPopControl::DoKey)
ENDDISPATCH

/*	XGPopControl::DoKey
 *
 *		Handle keyboard event. This only handles up, down keys
 */

long XGPopControl::DoKey(long arg, void *)
{
	short hi,lo;
	
	hi = GETHIWORD(arg);
	lo = GETLOWORD(arg);
	if (hi & KSpecialKey) {
		switch (lo) {
			case KKeyUpCursor:
				SetValue(GetValue()-1);
				DoDispatch(KXGPopValue,GetViewID(),NULL);
				return 0;
			case KKeyDownCursor:
				SetValue(GetValue()+1);
				DoDispatch(KXGPopValue,GetViewID(),NULL);
				return 0;
		}
	}
	return -1;
}
