#include "ScrollPane.h"#define ViewHeight() (mFrame.bottom-mFrame.top - (mHBar ? 16 : 0))#define ViewWidth() (mFrame.right-mFrame.left - (mVBar ? 16 : 0))ScrollPane::ScrollPane( WindowPtr pWindow, const Boolean hasHBar, const Boolean hasVBar ): mHBar(0L), mVBar(0L), mContent(0L), mOwnsContent(true), mBorder(true){	mReserve.h = mReserve.v = 0;	mSize.h = mSize.v = 200;	if (hasHBar) {		mHBar = new ScrollbarPane( pWindow );	}	if (hasVBar) {		mVBar = new ScrollbarPane( pWindow );	}	Adjust();}ScrollPane::~ScrollPane(){	if (mHBar) delete mHBar;	if (mVBar) delete mVBar;	if (mContent and mOwnsContent) delete mContent;}Point ScrollPane::GetTopLeft() const{	Point p = { mVBar ? mVBar->GetValue() : 0,				mHBar ? mHBar->GetValue() : 0 };	return p;}void ScrollPane::SetTopLeft( const Point p ){	if (mHBar) {		short val = p.h;		if (val < 0) val = 0;		if (val > mHBar->GetMaximum()) val = mHBar->GetMaximum();		mHBar->SetValue( val );	}	if (mVBar) {		short val = p.v;		if (val < 0) val = 0;		if (val > mVBar->GetMaximum()) val = mVBar->GetMaximum();		mVBar->SetValue( val );	}}void ScrollPane::Adjust(){	short max;	if (mHBar) {		mHBar->mFrame = CalcHBarRect();		mHBar->mPageRate = ViewWidth();		max = mSize.h - mHBar->mPageRate;		if (max < 0) max = 0;		mHBar->SetMaximum( max );		if (mHBar->GetValue() > max)			mHBar->SetValue( max );		mHBar->FitFrame();	}	if (mVBar) {		mVBar->mFrame = CalcVBarRect();		mVBar->mPageRate = ViewHeight();		max = mSize.v - mVBar->mPageRate;		if (max < 0) max = 0;		mVBar->SetMaximum( max );		if (mVBar->GetValue() > max)			mVBar->SetValue( max );		mVBar->FitFrame();	}}Rect ScrollPane::CalcHBarRect(){	Rect r = {	mFrame.bottom - 16,				mFrame.left + mReserve.h,				mFrame.bottom,				mFrame.right - (mVBar ? 15 : 0) };	return r;}Rect ScrollPane::CalcVBarRect(){	Rect r = {	mFrame.top + mReserve.v,				mFrame.right - 16,				mFrame.bottom - (mHBar ? 15 : 0),				mFrame.right };	return r;}Rect ScrollPane::CalcContentRect(){	Rect r = {	mFrame.top,				mFrame.left,				mFrame.bottom - (mHBar ? 15 : 0),				mFrame.right - (mVBar ? 15 : 0) };	return r;}void ScrollPane::SetContentPane( Pane *pane, const Boolean takeOwnership ){	// set internal variables	if (mContent and mOwnsContent) delete mContent;	mContent = pane;	mOwnsContent = takeOwnership;	// if a null pane, do nothing more	if (!pane) return;		// adjust size to size of the pane	mSize.h = pane->mFrame.right - pane->mFrame.left;	mSize.v = pane->mFrame.bottom - pane->mFrame.top;	Adjust();}void ScrollPane::Draw(){	if (mHidden) return;	// draw scroll bars	if (mHBar) mHBar->Draw();	if (mVBar) mVBar->Draw();	// draw contents	DrawContent();	// if we have reserved space, erase that	if (mReserve.h and mHBar) {		Rect r = {	mFrame.bottom-15, mFrame.left,					mFrame.bottom, mFrame.left + mReserve.h };		EraseRect( &r );	}	if (mReserve.v and mVBar) {		Rect r = {	mFrame.top, mFrame.right-15, 					mFrame.top + mReserve.v, mFrame.right };		EraseRect( &r );	}	}void ScrollPane::DrawContent(){	if (!mContent) return;	// find document position	GrafPtr port;	GetPort( &port );	Point original = { port->portRect.top, port->portRect.left };		Point scrolledTo = GetTopLeft();	Point docTopLeft = { original.v - mFrame.top  + scrolledTo.v,						 original.h - mFrame.left + scrolledTo.h };	// change drawing origin	SetOrigin( docTopLeft.h, docTopLeft.v );		// set clipping rect (relative to newly set origin)	RgnHandle saveClipRgn = NewRgn();	/* get an empty region */	GetClip( saveClipRgn );				/* save current */	Rect r = { scrolledTo.v, scrolledTo.h, 				scrolledTo.v + ViewHeight(),				scrolledTo.h + ViewWidth()};	ClipRect( &r );	// erase old stuff (especially important when content pane	// is not centered, or does not fully cover the view pane)	Rect r2 = { 0, 0, r.bottom-r.top, r.right-r.left };	if (r2.left < mContent->mFrame.left or r2.right > mContent->mFrame.right		or r2.top < mContent->mFrame.top or r2.bottom > mContent->mFrame.bottom) {		// NOTE: for better performance, we could calculate only the		// non-overlapping region, and erase that instead of the whole thing		EraseRect( &r );	}		// then, draw the content pane	mContent->Draw();		// if desired, draw a border	if (mBorder) {		if (mHBar) r.bottom++;	// make border overlap scroll bar border		if (mVBar) r.right++;		ClipRect( &r );		FrameRect( &r );	}		// restore the port origin and clipping region	SetOrigin( original.h, original.v );	SetClip( saveClipRgn );				/* restore previous value */	DisposeRgn( saveClipRgn );			/* not needed any more */}Boolean ScrollPane::Click(Point p, short modifiers){	// did we hit a control part?	if (mHBar and mHBar->Contains(p)) {		mHBar->Click(p, modifiers );	} else if (mVBar and mVBar->Contains(p)) {		mVBar->Click(p, modifiers );	} 	// or how about the content region?	else if (PtInRect( p, &CalcContentRect() )){		// we must adjust the click to reflect the scrolling!		Point topleft = GetTopLeft();		p.h += topleft.h;		p.v += topleft.v;		return mContent->Click(p,modifiers);	}	else {		// none of the above?  (must be a reserved space...)		// return false, indicating that we didn't deal with it		return false;	}	// refresh the content region (probably scrolled)	DrawContent();	return true;}
