/*********************************************************************
 * EditScrollBar.c
 *
 * HexEdit, a simple hex editor
 * copyright 1993, Jim Bumgardner
 *********************************************************************/
#include "HexEdit.h"

ControlActionUPP trackActionUPP;		//LR :init'd in Main!

void HEditScrollToPosition(EditWindowPtr dWin, long newPos);
void AdjustScrollBars(WindowPtr theWin, short resizeFlag);

void SetupScrollBars(EditWindowPtr dWin)
{
	Rect	sRect,r;
	// !! Set up vertical scroll bar
	//
	r = ((WindowPtr) dWin)->portRect;
	sRect.left = r.right - (SBarSize - 1);
	sRect.top = r.top - 1;
	sRect.right = r.right + 1;
	sRect.bottom = r.bottom  - GrowIconSize;
 	dWin->vScrollBar = NewControl((WindowPtr) dWin,&sRect,"\p",true,
 								0,0,sRect.bottom - sRect.top,scrollBarProc,1L);
	AdjustScrollBars((WindowPtr) dWin, 1);
}

//
// Adjust scroll bars when they need to be redrawn for some reason.
//
// resizeFlag is an optimization to avoid extra work when you aren't
// resizing.
//

void AdjustScrollBars(WindowPtr theWin, short resizeFlag)
{
	short			w,h;
	GrafPtr			savePort;
	EditWindowPtr	dWin = (EditWindowPtr) theWin;
	long			limit;

	GetPort(&savePort);

	if (resizeFlag) {
		// Adjust Lines Per Page
		dWin->linesPerPage = ((theWin->portRect.bottom - SBarSize) - HeaderHeight - TopMargin - BotMargin)/LineHeight;

		// Move sliders to new position
		//
		MoveControl(dWin->vScrollBar, theWin->portRect.right - (SBarSize - 1),
											theWin->portRect.top - 1);	
		// Change their sizes to fit new window dimensions
		//
		w = 16;
		h = theWin->portRect.bottom - theWin->portRect.top - (GrowIconSize - 1);
		SizeControl(dWin->vScrollBar,w,h);

		// Reset their maximum values
		//
		SetCtlMax(dWin->vScrollBar,h);
	}

	// Reposition painting if you have resized or scrolled past the legal
	// bounds  Note: this call will usually be followed by an update
	//
	limit = ((dWin->fileSize+15) & 0xFFFFFFF0) - (dWin->linesPerPage << 4);
	if (dWin->editOffset > limit)
		dWin->editOffset = limit;
	if (dWin->editOffset < 0)
		dWin->editOffset = 0;

	// Set the value of the sliders accordingly
	//
	h = theWin->portRect.bottom - theWin->portRect.top - (GrowIconSize - 1);
	if (limit > 0) {
		h = theWin->portRect.bottom - theWin->portRect.top - (GrowIconSize - 1);
		SetCtlMax(dWin->vScrollBar,h);
		if (dWin->editOffset < 64000L)
			SetCtlValue(dWin->vScrollBar,(short) ((dWin->editOffset*h)/limit));
		else
			SetCtlValue(dWin->vScrollBar,(short) (dWin->editOffset / (limit/h)));
	}
	else {
		SetCtlMax(dWin->vScrollBar,0);
		SetCtlValue(dWin->vScrollBar,0);
	}
		
	SetPort(savePort);
}

//
// Callback routine to handle arrows and page up, page down
//
EditWindowPtr	gDWin;

pascal void MyScrollAction(ControlHandle theControl, short thePart)
{
#pragma unused (theControl)	//LR :fix warnings

	long		curPos,newPos;
	short		pageWidth;
	Rect		myRect;
	WindowPtr	gp = (WindowPtr) gDWin;

	curPos = gDWin->editOffset;
	newPos = curPos;

	myRect = ((WindowPtr) gDWin)->portRect;
	myRect.right -= SBarSize-1;
	myRect.bottom -= SBarSize-1;

	pageWidth = (gDWin->linesPerPage-1)*16;

	switch (thePart) {
	  case inUpButton:		newPos = curPos - 16;			break;
	  case inDownButton:	newPos = curPos + 16;			break;
  	  case inPageUp:		newPos = curPos - pageWidth;	break;
	  case inPageDown:		newPos = curPos + pageWidth;	break;
	}

	if (newPos != curPos) {
		HEditScrollToPosition(gDWin, newPos);
	}
}

// Intercept Handler for scroll bars
// Returns true if user clicked on scroll bar
//

Boolean HandleControlClick(WindowPtr theWin, Point where)
{
	short 			ctlPart;
	ControlHandle	whichControl;
	short			vPos;
	EditWindowPtr	dWin = (EditWindowPtr) theWin;
	ControlActionUPP trackActionProc;

	// Check if user clicked on scrollbar
	//
	if ((ctlPart = FindControl(where,theWin,&whichControl)) == 0)
		return false;

	// Identify window for callback procedure
	//
	gDWin = dWin;

	// Use default behavior for thumb
	// Program will crash if you don't!!
	//
	if (ctlPart == inThumb)
		trackActionProc = 0L;
	else
		trackActionProc = trackActionUPP;	//LR :Universal Headers requirement fix

	// Perform scrollbar tracking
	//
	if ((ctlPart = TrackControl(whichControl, where, trackActionProc)) == 0)	//LR :see above
		return false;

	if (ctlPart == inThumb) {
		long	newPos,h,limit;
		vPos = GetCtlValue(dWin->vScrollBar);
		h = theWin->portRect.bottom - theWin->portRect.top - (GrowIconSize - 1);
		limit = ((dWin->fileSize+15) & 0xFFFFFFF0) - (dWin->linesPerPage << 4);
		if (vPos == h)
			newPos = ((dWin->fileSize+15) & 0xFFFFFFF0) - (dWin->linesPerPage << 4);
		else if (limit < 64000L)		// JAB 12/10 Prevent Overflow in Calcuation
			newPos = (vPos*limit)/h;
		else
			newPos = vPos*(limit/h);
		newPos -= newPos & 0x0F;
		HEditScrollToPosition(dWin, newPos);
	}

	return true;
}

// Scroll to an explicit position
//
void HEditScrollToPosition(EditWindowPtr dWin, long newPos)
{
	long	limit;

	SetPort((WindowPtr) dWin);

	// Constrain scrolling position to legal limits
	//
	limit = ((dWin->fileSize+15) & 0xFFFFFFF0) - (dWin->linesPerPage << 4);
	if (newPos > limit)
		newPos = limit;
	if (newPos < 0)
		newPos = 0;
	dWin->editOffset = newPos;
	
	// Adjust Scrollbars
	AdjustScrollBars((WindowPtr) dWin, false);

	// 12/10/93 - Optimize Drawing
	SetCurrentChunk(dWin, dWin->editOffset);

	DrawPage(dWin);
	UpdateOnscreen((WindowPtr) dWin);
}

void AutoScroll(EditWindowPtr dWin, Point pos)
{
	short	offset;
	if (pos.v < HeaderHeight+TopMargin)
		offset = -16;
	else if (pos.v >= HeaderHeight+TopMargin+dWin->linesPerPage*LineHeight)
		offset = 16;
	else
		return;
	HEditScrollToPosition(dWin, dWin->editOffset+offset);
}