/*	XGScrollView.cpp
 *
 *		Scrollbar positioning and scrolling view management
 */

/*  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 <XMessages.h>
#include <XScroll.h>
#include <XDraw.h>

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

/*	@F"XGScrollView::XGScrollView" @I
 *
 *		Construct me
 */

XGScrollView::XGScrollView(XGOwner *parent, XGArgStream &stream) : XGView(parent,stream)
{
	XGSScrollViewInit init;
	
	init.fHScroll = stream.ReadBoolean();
	init.fVScroll = stream.ReadBoolean();
	init.fCorner  = stream.ReadBoolean();
	InitScrollView(init);
}

XGScrollView::XGScrollView(XGOwner *parent, XGSScrollViewInit &init) : XGView(parent,init.view)
{
	InitScrollView(init);
}

/*	@F"XGScrollView::~XGScrollView" @I
 *
 *		Delete these
 */

XGScrollView::~XGScrollView()
{
	if (fHoriz) delete fHoriz;
	if (fVert)  delete fVert;
}

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

/*	@F"XGScrollView::DoDrawView" @I
 *
 *		Draw the corner if it's visible
 */

void XGScrollView::DoDrawView(Rect)
{
	XGDraw draw(this);
	Rect r;

	r = GetContentRect();
	draw.Draw3DRect(r,KXGEFrame);
	
	if (!fCorner) return;
	r = CalcCornerRect();
	draw.Draw3DRect(r,KXGEBackground);
}

/*	@F"XGScrollView::CalcChildPos" @I
 *
 *		Set the position of the children. This
 */

Rect XGScrollView::CalcChildPos(XGView *view)
{
	if (view == fHoriz) {
		return CalcHScroll();
	} else if (view == fVert) {
		return CalcVScroll();
	} else {
		return view->CalcAutoLocate(CalcContentRect());
	}
}

/************************************************************************/
/*																		*/
/*	Scrollbar Management												*/
/*																		*/
/************************************************************************/

/*	@F"XGScrollView::SetScrollValue" @I
 *
 *		Set the scrollbar values
 */

void XGScrollView::SetScrollValue(long x, long y)
{
	if (fHoriz) fHoriz->SetValue(x);
	if (fVert) fVert->SetValue(y);
}

/*	@F"XGScrollView::SetMinValue" @I
 *
 *		Set the scrollbar values
 */

void XGScrollView::SetMinValue(long x, long y)
{
	if (fHoriz) fHoriz->SetMinValue(x);
	if (fVert) fVert->SetMinValue(y);
}

/*	@F"XGScrollView::SetMaxValue" @I
 *
 *		Set the scrollbar values
 */

void XGScrollView::SetMaxValue(long x, long y)
{
	if (fHoriz) fHoriz->SetMaxValue(x);
	if (fVert) fVert->SetMaxValue(y);
}

/*	@F"XGScrollView::SetStepSize" @I
 *
 *		Set the scrollbar values
 */

void XGScrollView::SetStepSize(long x)
{
	if (fHoriz) fHoriz->SetStepSize(x);
	if (fVert) fVert->SetStepSize(x);
}

/*	@F"XGScrollView::SetPageSize" @I
 *
 *		Set the scrollbar values
 */

void XGScrollView::SetPageSize(long x, long y)
{
	if (fHoriz) fHoriz->SetPageSize(x);
	if (fVert) fVert->SetPageSize(y);
}

/*	@F"XGScrollView::GetScrollValue" @I
 *
 *		Get the scrollbar values
 */

void XGScrollView::GetScrollValue(long *x, long *y)
{
	*x = fHoriz ? fHoriz->GetValue() : 0;
	*y = fVert  ? fVert->GetValue()  : 0;
}

/*	@F"XGScrollView::GetMinValue" @I
 *
 *		Get the scrollbar values
 */

void XGScrollView::GetMinValue(long *x, long *y)
{
	*x = fHoriz ? fHoriz->GetMinValue() : 0;
	*y = fVert  ? fVert->GetMinValue()  : 0;
}

/*	@F"XGScrollView::GetMaxValue" @I
 *
 *		Get the scrollbar values
 */

void XGScrollView::GetMaxValue(long *x, long *y)
{
	*x = fHoriz ? fHoriz->GetMaxValue() : 0;
	*y = fVert  ? fVert->GetMaxValue()  : 0;
}

/*	@F"XGScrollView::GetStepSize" @I
 *
 *		Get the scrollbar values
 */

long XGScrollView::GetStepSize()
{
	if (fHoriz) return fHoriz->GetStepSize();
	if (fVert) return fVert->GetStepSize();
	return 1;
}

/*	@F"XGScrollView::GetPageSize" @I
 *
 *		Get the scrollbar values
 */

void XGScrollView::GetPageSize(long *x, long *y)
{
	*x = fHoriz ? fHoriz->GetPageSize() : 0;
	*y = fVert  ? fVert->GetPageSize()  : 0;
}

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

BEGINDISPATCH(XGScrollView,XGView)
	DISPATCHTABLE(KXGSliderStart,XGScrollView::DoSliderStart)
	DISPATCHTABLE(KXGSliderValue,XGScrollView::DoSliderValue)
ENDDISPATCH

/*	XGScrollView::DoSliderStart
 *
 *		Start the slider by updating the content rectangles. This makes
 *	sure the update regions are filled in before we start moving bits
 *	around; that way the bits are correct...
 */

long XGScrollView::DoSliderStart(long, void *)
{
	XGView *view;
	for (view = GetChild(); view != NULL; view = view->GetSibling()) {
		if (view == fHoriz) continue;
		if (view == fVert) continue;
		
		view->UpdateView();
	}
	return 0;
}

/*	XGScrollView::DoSliderValue
 *
 *		Update the value from this control
 */

long XGScrollView::DoSliderValue(long, void *ptr)
{
	long dx,dy;
	XGSValue *value = (XGSValue *)ptr;
	XGView *view;
	
	if (value->slider == fHoriz) {
		dy = 0;
		dx = value->oldVal - value->newVal;
	} else {
		dx = 0;
		dy = value->oldVal - value->newVal;
	}
	
	for (view = GetChild(); view != NULL; view = view->GetSibling()) {
		if (view == fHoriz) continue;
		if (view == fVert) continue;
		
		view->Scroll(dx*fPixel,dy*fPixel);				// scroll and draw
		view->UpdateView();
	}
	return 0;
}

/************************************************************************/
/*																		*/
/*	Internals															*/
/*																		*/
/************************************************************************/

/*	XGScrollView::InitScrollView
 *
 *		Initialize the scroll view
 */

void XGScrollView::InitScrollView(XGSScrollViewInit &s)
{
	XGSScrollInitRecord sinit;
	Rect r;
	Rect c;

	fPixel = 1;
	
	fCorner = s.fCorner;
	if (s.fHScroll && s.fVScroll) fCorner = true;
	
	c = GetContentRect();
	if (s.fHScroll) {
		r = CalcHScroll();
		sinit.view.fViewType = XGScrollBar::kClassID;
		sinit.view.fViewID = 0;
		sinit.view.fRefNum = 0;
		
		sinit.view.fLockLeft = true;
		sinit.view.fLockTop = true;
		sinit.view.fLockRight = true;
		sinit.view.fLockBottom = true;
		
		sinit.view.fAutoLeft = r.left;
		sinit.view.fAutoTop = r.top;
		sinit.view.fAutoRight = c.right - r.right;
		sinit.view.fAutoBottom = c.bottom - r.bottom;
		
		sinit.view.fVisible = true;
		sinit.view.fEnabled = true;
		sinit.view.fTabStop = false;
		
		sinit.fValue = 0;
		sinit.fMinValue = 0;
		sinit.fMaxValue = 0;
		sinit.fStepValue = 1;
		sinit.fPageValue = 1;
		
		fHoriz = new XGScrollBar(this,sinit);
		fHoriz->SetLocation(CalcChildPos(fHoriz));
	} else {
		fHoriz = NULL;
	}
	
	if (s.fVScroll) {
		r = CalcVScroll();
		sinit.view.fViewType = XGScrollBar::kClassID;
		sinit.view.fViewID = 0;
		sinit.view.fRefNum = 0;
		
		sinit.view.fLockLeft = true;
		sinit.view.fLockTop = true;
		sinit.view.fLockRight = true;
		sinit.view.fLockBottom = true;
		
		sinit.view.fAutoLeft = r.left;
		sinit.view.fAutoTop = r.top;
		sinit.view.fAutoRight = c.right - r.right;
		sinit.view.fAutoBottom = c.bottom - r.bottom;
		
		sinit.view.fVisible = true;
		sinit.view.fEnabled = true;
		sinit.view.fTabStop = false;
		
		sinit.fValue = 0;
		sinit.fMinValue = 0;
		sinit.fMaxValue = 0;
		sinit.fStepValue = 1;
		sinit.fPageValue = 1;
		
		fVert = new XGScrollBar(this,sinit);
		fVert->SetLocation(CalcChildPos(fVert));
	} else {
		fVert = NULL;
	}
}

/************************************************************************/
/*																		*/
/*	Locations															*/
/*																		*/
/************************************************************************/

/*	XGScrollView::CalcHScroll
 *
 *		Calculate the horizontal view
 */

Rect XGScrollView::CalcHScroll()
{
	Rect r;
	Point pt;
	
	pt = XGScrollBar::GetDefaultSize();
	r = GetContentRect();
	::InsetRect(&r,1,1);

#if OPT_MACOS || OPT_XWIN
	r.left--;
	r.right++;
	r.bottom++;
	r.top = r.bottom - pt.v;
	if (fCorner) r.right -= pt.h - 1;
#endif

#if OPT_WINOS
	r.top = r.bottom - pt.v;
	if (fCorner) r.right -= pt.h;
#endif

	return r;
}

/*	XGScrollView::CalcVScroll
 *
 *		Calculate the horizontal view
 */

Rect XGScrollView::CalcVScroll()
{
	Rect r;
	Point pt;
	
	pt = XGScrollBar::GetDefaultSize();
	r = GetContentRect();
	::InsetRect(&r,1,1);

#if OPT_MACOS || OPT_XWIN
	r.top--;
	r.right++;
	r.bottom++;
	r.left = r.right - pt.h;
	if (fCorner) r.bottom -= pt.v - 1;
#endif

#if OPT_WINOS
	r.left = r.right - pt.h;
	if (fCorner) r.bottom -= pt.v;
#endif

	return r;
}

/*	XGScrollView::CalcCornerRect
 *
 *		Calculate the size of the corner
 */

Rect XGScrollView::CalcCornerRect()
{
	Rect r;
	Point pt;
	
	pt = XGScrollBar::GetDefaultSize();
	r = GetContentRect();
	::InsetRect(&r,1,1);

#if OPT_MACOS || OPT_XWIN
	r.left = r.right - pt.h + 2;
	r.top = r.bottom - pt.v + 2;
#endif

#if OPT_WINOS
	r.left = r.right - pt.h;
	r.top = r.bottom - pt.v;
#endif

	return r;
}

/*	XGScrollView::CalcContentRect
 *
 *		Calculate the size of the corner
 */

Rect XGScrollView::CalcContentRect()
{
	Rect r;
	Point pt;
	
	pt = XGScrollBar::GetDefaultSize();
	r = GetContentRect();
	::InsetRect(&r,1,1);

#if OPT_MACOS || OPT_XWIN
	if (fVert)  r.right -= pt.h - 1;
	if (fHoriz) r.bottom -= pt.v - 1;
#endif

#if OPT_WINOS
	if (fVert)  r.right -= pt.h;
	if (fHoriz) r.bottom -= pt.v;
#endif

	return r;
}
