/*	XGButton.cpp
 *
 *		This is the base control for all my buttons. On the
 *	Macintosh and on Microsoft Windows, this manages the generic
 *	control object. On X, this really doesn't do very much...
 */

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

  YAAF is Copyright 1997-1999 by William Woody.

  Redistribution and use in source and binary forms, with or without 
  modification, are permitted provided that the following conditions 
  are met:

  Redistributions of source code must retain the above copyright notice, 
  this list of conditions and the following disclaimer.

  Neither the name of the copyright holder or other contributors may
  be used to promote products derived from this software without
  specific written prior permission.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 
  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
  SOFTWARE.
  
  Contact:   woody@alumni.caltech.edu
  Web page:  http://www.pandawave.com/yaaf/

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

#include <XConfig.h>			// must be first to optimize compile on MSVC++
#include <string.h>
#include <XButtons.h>
#include <XDraw.h>
#include <XMessages.h>
#include <XCursorUtil.h>

/************************************************************************/
/*																		*/
/*	Construction/Destruction											*/
/*																		*/
/************************************************************************/

/*$	XGButton::XGButton
 *
 *		Construct me.
 */

XGButton::XGButton(XGView *v, XGArgStream &s) : XGControl(v,s)
{
	int i;
	
	i = s.ReadInteger();
	fFont = XGFont::LoadFont(i);

#if OPT_MACOS || OPT_WINOS
	fControl = NULL;
#endif

#if OPT_XWIN
	fValue = 0;
	fName[0] = 0;
#endif

#if OPT_MACOS
	ClearTabStop();
#endif
}

/*$	XGButton::~XGButton
 *
 *		Destruct me
 */

XGButton::~XGButton()
{
#if OPT_MACOS
	if (fControl) ::DisposeControl(fControl);
#endif

#if OPT_WINOS
	if (fControl) ::DestroyWindow(fControl);
#endif

	if (fFont) fFont->Detach();
}

/************************************************************************/
/*																		*/
/*	Control's value														*/
/*																		*/
/************************************************************************/

/*$	XGButton::GetValue
 *
 *		Get the value of this thing
 */

long XGButton::GetValue(void)
{
#if OPT_MACOS
	if (!fControl) return 0;
	return (long)::GetControlValue(fControl);
#endif

#if OPT_WINOS
	long result;
	
	if (!fControl) return 0;
	result = (long)::SendMessage(fControl,BM_GETCHECK,0,0);
	switch (result) {
		case BST_UNCHECKED:
		default:
			return 0;
		case BST_CHECKED:
			return 1;
		case BST_INDETERMINATE:
			return -1;
	}
#endif

#if OPT_XWIN
	return fValue;
#endif
}

/*$	XGButton::SetValue
 *
 *		Set the value of this thing
 */

void XGButton::SetValue(long value)
{
#if OPT_MACOS
	if (fControl) {
		/* The MacOS redraws the control, so this makes sure */
		/* the Mac grafport is set up correctly */
		XGDraw draw(this,false);
		if (fFont) {
			fFont->Attach();
			draw.SetFont(fFont);
		}
		::SetControlValue(fControl,value);
	}
#endif

#if OPT_WINOS
	if (fControl) {
		WPARAM w;
		
		switch (value) {
			case 0:
			default:
				w = BST_UNCHECKED;
				break;
			case 1:
				w = BST_CHECKED;
				break;
			case 2:
				w = BST_INDETERMINATE;
				break;
		}
		::SendMessage(fControl,BM_SETCHECK,w,0);
	}
#endif

#if OPT_XWIN
	fValue = value;
	InvalView();
#endif
}


/*$	XGButton::PushButton
 *
 *		Temporary push button act, and return message. This does the
 *	appropriate thing on the target platform
 */

void XGButton::PushButton()
{
	if (!IsEnabled() && !IsActive()) return;

#if OPT_MACOS
	unsigned long tmp;
	XGDraw draw(this,false);
	if (fFont) {
		fFont->Attach();
		draw.SetFont(fFont);
	}
	
	::HiliteControl(fControl,kControlButtonPart);
	::Delay(5,&tmp);
	::HiliteControl(fControl,0);
	DoDispatch(KXGControlClick,GetViewID(),NULL);
#endif

#if OPT_WINOS
	::SendMessage(fControl,BM_CLICK,0,0);		// simulate click
#endif

#if OPT_XWIN
	DoDispatch(KXGControlClick,GetViewID(),NULL);
#endif
}

/************************************************************************/
/*																		*/
/*	Events																*/
/*																		*/
/************************************************************************/

/*$	XGButton::DoDrawView
 *
 *		Handle the drawing
 */

void XGButton::DoDrawView(XRect)
{
#if OPT_MACOS
	if (fControl) {
		XGDraw draw(this,false);
		if (fFont) {
			fFont->Attach();
			draw.SetFont(fFont);
		}
		
		if (IsEnabled() && IsActive()) {
			/*
			 *	Enabled
			 */
			
			::HiliteControl(fControl,0);
		} else {
			::HiliteControl(fControl,255);
		}
		::ShowControl(fControl);
		::Draw1Control(fControl);
	}
#endif

#if OPT_WINOS
	if (fControl) {
		/*
		 *	The invalidate here may seem a little wierd, but this
		 *	causes the control to redraw itself separately, and after
		 *	this draw view command is issued. The upshot of this is
		 *	that the control is forced to be redrawn.
		 */
		
		::ShowWindow(fControl,SW_SHOW);
		::InvalidateRect(fControl,NULL,false);
	}
#endif

#if OPT_XWIN
	DrawControl(false);
#endif
}

/*$	XGButton::DoActivate
 *
 *		Activate/deactivate.
 */

void XGButton::DoActivate(bool)
{
#if OPT_MACOS || OPT_XWIN
	if (IsEnabled()) {
		InvalView();
	}
#endif

#if OPT_WINOS
	/* Does nothing; activation/deactivation handled automatically */
#endif
}

/*$	XGButton::DoMouseDown
 *
 *		Handle the mouse down event. Only used for the Macintosh
 */

bool XGButton::DoMouseDown(XPoint pt, short a)
{
#if OPT_MACOS
	if (fControl) {
		XGDraw draw(this,false);
		if (fFont) {
			fFont->Attach();
			draw.SetFont(fFont);
		}
		ViewToGlobal(&pt);
		if (::TrackControl(fControl,pt.MacPoint(),NULL)) {
			DoDispatch(KXGControlClick,GetViewID(),NULL);
		}
	} else {
		XGControl::DoMouseDown(pt,a);
	}
	return false;
#endif

#if OPT_WINOS
	return XGControl::DoMouseDown(pt,a);
#endif

#if OPT_XWIN
	fDown = true;
	DrawControl(true);
	return true;
#endif
}

/*$	XGButton::DoMouseMove
 *
 *		handle mouse move events
 */

void XGButton::DoMouseMove(XPoint pt, short a)
{
#if OPT_XWIN
	XRect r;
	
	if (a & KCapturedMouse) {
		r = GetContentRect();

		if (PtInRect(pt,&r)) {
			if (!fDown) {
				fDown = true;
				DrawControl(true);
			}
		} else {
			if (fDown) {
				fDown = false;
				DrawControl(false);
			}
		}
	} else {
		::SetCursorID(KNormalCursor);
	}
#else
	XGControl::DoMouseMove(pt,a);
#endif
}

/*$	XGButton::DoMouseUp
 *
 *		handle mouse up
 */

void XGButton::DoMouseUp(XPoint pt, short a)
{
#if OPT_XWIN
	if (fDown) {
		DrawControl(false);
		DoDispatch(KXGControlClick,GetViewID(),NULL);
	}
#else
	XGControl::DoMouseUp(pt,a);
#endif
}

/*$	XGButton::GetTitle
 *
 *		Get the name
 */

void XGButton::GetTitle(char *name) const
{
#if OPT_MACOS
	::GetControlTitle(fControl,(unsigned char *)name);
	p2cstr((unsigned char *)name);
#endif

#if OPT_WINOS
	::SendMessage(fControl,WM_GETTEXT,255,(LPARAM)(LPSTR)name);
#endif

#if OPT_XWIN
	::strcpy(name,fName);
#endif
}

/*$	XGButton::SetTitle
 *
 *		Set the name
 */

void XGButton::SetTitle(const char *name)
{
#if OPT_MACOS
	char buffer[256];
	
	strcpy(buffer,name);
	XGDraw draw(this,false);
	if (fFont) {
		fFont->Attach();
		draw.SetFont(fFont);
	}
	::SetControlTitle(fControl,c2pstr(buffer));
#endif

#if OPT_WINOS
	::SendMessage(fControl,WM_SETTEXT,0,(LPARAM)(LPSTR)name);
#endif

#if OPT_XWIN
	::strcpy(fName,name);
	InvalView();
#endif
}

/*$	XGButton::DoSizeView
 *
 *		Handle resize event
 */

void XGButton::DoSizeView()
{
#if OPT_MACOS || OPT_WINOS
	DoMoveView();
#endif

	/*
	 *	Pass upwards
	 */
	
	XGControl::DoSizeView();
}

/*$	XGButton::DoMoveView
 *
 *		Move the view.
 */

void XGButton::DoMoveView()
{
#if OPT_MACOS || OPT_WINOS
	XRect r;
	
	if (!fControl) return;
	r = GetContentRect();
	ViewToGlobal(&r);
	
#if OPT_MACOS
	XGDraw draw(this,false);
	if (fFont) {
		fFont->Attach();
		draw.SetFont(fFont);
	}
	::HideControl(fControl);
	::MoveControl(fControl,r.left,r.top);
	::SizeControl(fControl,r.right-r.left,r.bottom-r.top);
#endif

#if OPT_WINOS
	::SetWindowPos(fControl,
				   NULL,
				   r.left,
				   r.top,
				   r.right-r.left,
				   r.bottom-r.top,
				   SWP_NOZORDER | SWP_HIDEWINDOW);
#endif
#endif
}

/*$	XGButton::DoShowHide
 *
 *		This is called when the control is to be hidden or
 *	shown. This only needs to hide the control; the call to
 *	DoDrawView() will show the control if needed.
 */

void XGButton::DoShowHide()
{
#if OPT_MACOS
	if (!IsVisible() && fControl) {
		XGDraw draw(this,false);
		if (fFont) {
			fFont->Attach();
			draw.SetFont(fFont);
		}
		::HideControl(fControl);
		::MoveControl(fControl,-20,-20);
		::SizeControl(fControl,10,10);
	} else {
		if (fControl) {
			XRect r;
			
			r = GetContentRect();
			ViewToGlobal(&r);
			::MoveControl(fControl,r.left,r.top);
			::SizeControl(fControl,r.right-r.left,r.bottom-r.top);
		}
	}
#endif

#if OPT_WINOS
	if (!IsVisible() && fControl) {
		::ShowWindow(fControl,SW_HIDE);
	}
#endif

	XGView::DoShowHide();
}

/*$	XGButton::DoEnable
 *
 *		Handle enable/disable events. Passes the enable/disable
 *	event to the control
 */

void XGButton::DoEnable()
{
#if OPT_WINOS
	if (fControl) ::EnableWindow(fControl,IsEnabled());
#endif
}

#if OPT_WINOS

/*$	XGButton::SetFocus
 *
 *		Set the focus. This overrides stuff on Windows by setting the
 *	MS Window focus as well.
 */

void XGButton::SetFocus(void)
{
	XGControl::SetControlFocus(fControl);
}

#endif

/************************************************************************/
/*																		*/
/*	Windows Event Implementation										*/
/*																		*/
/************************************************************************/

#if OPT_WINOS

BEGINDISPATCH(XGButton,XGView)
	DISPATCHTABLE(KXGWInternal,XGButton::DoWInternal)
ENDDISPATCH

/*	XGButton::DoWInternal
 *
 *		This is where messages that are received from my
 *	control is sent
 */

long XGButton::DoWInternal(long,void *ptr)
{
	XGSWInternalRecord *r;
	
	r = (XGSWInternalRecord *)ptr;
	
	/*
	 *	How to handle this
	 */
	
	if (r->msg == WM_COMMAND) {
		if (HIWORD(r->wp) == BN_CLICKED) {
			/*
			 *	I've been clicked on
			 */
			
			DoDispatch(KXGControlClick,GetViewID(),NULL);
			return 0;
		}
	}
	return -1;
}

#endif
