/*	XGProgress.cpp
 *
 *		Progress control
 *		(c) 1999 Sassafas Software Inc.
 */

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

  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 <XPopup.h>
#include <XDraw.h>
#include <XWindow.h>
#include <XDataUtil.h>
#include <XMessages.h>
#include <XMisc.h>
#include <XApplication.h>
#include <XProgress.h>

#if OPT_MACOS
#include <appearance.h>
#include <string.h>
#endif

#if OPT_WINOS
#include <commctrl.h>
#endif

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

/*$	XGProgress::XGProgress
 *
 *		Pop up control
 */

XGProgress::XGProgress(XGView *parent, XGArgStream &s) : 
	XGSlider(parent,s)
{
	fValue = s.ReadInteger();
	fMin = s.ReadInteger();
	fMax = s.ReadInteger();
	fIndeterminate = s.ReadBoolean();
	if (fMax <= 16384)
		fScale = 1;
	else
		fScale = fMax / 16384;
#if OPT_WINOS
	InitControl();
#endif
#if OPT_MACOS
	ClearTabStop();
	InitControl();
#endif
}

/*$	XGProgress::~XGProgress
 *
 *		Delete me
 */

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

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

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

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

void
XGProgress::SetValue (long value)
{
	if (value >= fMax)
		value = fMax;
	if (value < fMin)
		value = fMin;
	if (fValue == value)
		return;
	fValue = value;
	
#if OPT_MACOS
	if (fControl) {
		XGDraw draw(this, false);
		::SetControlValue(fControl, fValue / fScale);
		return;
	}
#endif
#if OPT_WINOS
	if (fControl) {
		::SendMessage(fControl, PBM_SETPOS, fValue / fScale, 0);
		return;
	}
#endif

	/*
	 *	If we are here, it's either X, or we don't have a control
	 */
	
	XGDraw draw(this);
	DrawBar(draw);
}
 
void
XGProgress::SetMinValue (long min)
{
	if (fMin == min)
		return;
	fMin = min;
	if (fValue < fMin)
		fValue = fMin;
#if OPT_MACOS
	if (fControl) {
		XGDraw draw(this, false);
		SetControlMinimum(fControl, fMin / fScale);
		SetControlValue(fControl, fValue / fScale);
		return;
	}
#endif
#if OPT_WINOS
	if (fControl) {
		::SendMessage(fControl, PBM_SETRANGE, 0, MAKELPARAM(fMin / fScale, fMax / fScale));
		return;
	}
#endif

	InvalView();
}

void
XGProgress::SetMaxValue (long max)
{
	if (fMax == max) 
		return;
	fMax = max;
	if (fValue > fMax)
		fValue = fMax;
	if (fMax <= 16384)
		fScale = 1;
	else
		fScale = fMax / 16384;

#if OPT_MACOS
	if (fControl) {
		XGDraw draw(this, false);
		SetControlMaximum(fControl, fMax / fScale);
		SetControlValue(fControl, fValue / fScale);
		return;
	}
#endif
#if OPT_WINOS
	if (fControl) {
		::SendMessage(fControl, PBM_SETRANGE, 0, MAKELPARAM(fMin / fScale, fMax / fScale));
		return;
	}
#endif
	InvalView();
}

void
XGProgress::SetIndeterminate (bool indet)
{
	if (fIndeterminate == indet) 
		return;
	fIndeterminate = indet;
	
#if OPT_MACOS
	if (fControl) {
		char indon = fIndeterminate;
		SetControlData(fControl, 0, kControlProgressBarIndeterminateTag, 1, &indon);
		return;
	}
#endif
#if OPT_WINOS
	if (fControl) {
		/* not supported */
		return;
	}
#endif
	InvalView();
}


/************************************************************************/
/*																		*/
/*	Control Events														*/
/*																		*/
/************************************************************************/

/*$	XGProgress::DoDrawView
 *
 *		Draw the view.
 */

void XGProgress::DoDrawView(XRect)
{
#if OPT_MACOS
	if (fControl) {		
		XGDraw draw(this,false);
		if (IsEnabled() && IsActive()) {
			/*
			 *	Enabled
			 */
			
			::HiliteControl(fControl, 0);
		} else {
			::HiliteControl(fControl, 255);
		}
		::ShowControl(fControl);
		::Draw1Control(fControl);
		return;
	}
#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);
		return;
	}
#endif

	/* draw a generic progress bar */
	XGDraw draw(this);
	DrawBar(draw);
}

/*	XGProgress::DrawBar
 *
 *		Draw this view. This draws the status bar
 */

void XGProgress::DrawBar(XGDraw &draw)
{
	XRect r = GetContentRect();	
	short x;
	long min,max,val;
	XRect s;
	
	draw.Draw3DRect(r,KXGEFrame);
	::InsetRect(&r,1,1);
	
	min = fMin/fScale;
	max = fMax/fScale;
	val = fValue/fScale;
	
	if ((r.right - r.left) > (r.bottom - r.top)) {
		x = ((r.right - r.left) * (val - min)) / (max - min);
		
		s = r;
		s.left = r.right = x;
	} else {
		x = ((r.bottom - r.top) * (val - min)) / (max - min);
		
		s = r;
		s.top = r.bottom = x;
	}
	
	if (!::EmptyRect(&s)) draw.Draw3DRect(s,KXGEBackground);
	if (!::EmptyRect(&r)) {
		draw.FillRect(r,KXGColorBtnShadow);
	}
}


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

void
XGProgress::DoMoveView (void)
{
#if OPT_MACOS || OPT_WINOS
	XRect r;
	
	if (!fControl) {
		XGControl::DoMoveView();
		return;
	}

	r = GetContentRect();
	ViewToGlobal(&r);

#if OPT_MACOS
	XGDraw draw(this,false);
	::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
}

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

void
XGProgress::DoSizeView (void)
{
	DoMoveView();

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

/*$	XGProgress::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 XGProgress::DoShowHide()
{
#if OPT_MACOS
	if (fControl) {
		XGDraw draw(this,false);
		if (!IsVisible()) {
			::HideControl(fControl);
			::MoveControl(fControl,-20,-20);
			::SizeControl(fControl,10,10);
		} else {
			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 (fControl) {
		if (!IsVisible())
			::ShowWindow(fControl, SW_HIDE);
	}
#endif
	XGControl::DoShowHide();
}

/*$	XGProgress::DoActivate
 *
 *		Handle activate/deactivate
 */

void XGProgress::DoActivate(bool)
{
#if OPT_MACOS || OPT_XWIN
	if (IsEnabled())
		InvalView();
#endif
#if OPT_WINOS
	/* Does nothing; activation/deactivation handled automatically */
#endif
}

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

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

#if OPT_MACOS

/*$	XGProgress::InitControl
 *
 *		Initialize the control
 */

void XGProgress::InitControl (void)
{
	XRect r;

	fControl = NULL;
	if (!_GAppearance) return;

	if (IsVisible()) {
		r = GetContentRect();
		ViewToGlobal(&r);
	} else {
		r.left = -20,
		r.top = -20,
		r.right = -10,
		r.bottom = -10;
	}

	Rect mr = r.MacRect();
	fControl = ::NewControl(GetRootWindow(),
							&mr,
							"\p",
							false,
							fValue,
							fMin,
							fMax,
							kControlProgressBarProc,
							GetViewID());
}

#endif

#if OPT_WINOS

/*$	XGProgress::InitControl
 *
 *		Initialize the control
 */

void XGProgress::InitControl (void)
{
	XRect r;
	
	r = GetContentRect();
	ViewToGlobal(&r);
	fControl = ::CreateWindow(PROGRESS_CLASS,
							  "",
							  WS_CHILD,
							  r.left,
							  r.top,
							  r.right - r.left,
							  r.bottom - r.top,
							  GetRootWindow(),
							  NULL,
							  _GInstance,
							  NULL);
}

#endif

