/*------------------------------------------------------------------------------*
 * File Name:				 													*
 * Creation: 																	*
 * Purpose: OriginC Source C file												*
 * Copyright (c) ABCD Corp.	2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	Hong 03/07/07 QA80-9286-P7 FIX_ERROR_POSITION_FOR_VERTICAL_THUMB_LINE_WHEN_MOVING	*
 *	Hong 03/07/07 QA80-9286-S4 RESCALE_LAYER_BY_RANGE_ON_INIT					*
 *	Hong 03/08/07 UPDATE_POSTION_IF_ALREAY_EXISTING								*
 *	Hong 03/09/07 FIX_ZOOM_MENU_FAIL_TO_WORK									*
 *	Hong 03/15/07 EXPAND_5_PERCENT_SPACE_TO_BAR_BY_INIT_INDICATE_SCROLL_THUMB	*
 *	Hong 03/23/07 v8.0588 MORE_OPTION_ALLOW_NOT_RESCALE_ON_INIT					*
 *	Hong 03/23/07 V8.0588 ALLOW_DELETE_SCROLLBAR								*
 *	Hong 03/27/07 v8.0590 QA80-9286-P9 FIX_Y_SCROLLBAR_FAIL_UPDATE_LINK			*
 *	Hong 03/27/07 v8.0590 FIX_RESET_SCALE_THUMB_NOT_CORRECT_UPDATE				*
 *	Hong 03/27/07 V8.0590 FIX_Y_AXIS_FAIL_ADD_SPACE_AS_X						*
 *	Hong 03/29/07 v8.0592 ADD_MIN_THUMB_RESTRICTION								*
 *	CPY 4/29/07 SEPARATE_ZOOM_SCROLL_RANGE_AND_AXIS_RANGE						*
 *	Hong 05/05/07 QA80-9716 ADD_PLOT_CONTROL_XF_FOR_GRAPH_WINDOW				*
 *	Hong 06/05/07 QA80-9286-P10 FIX_THUMB_SIZE_NOT_CORRECT_AFTER_MOVED			*
 *	Hong 11/05/07 v8.0740 FIX_EXP_GRAPH_FAIL_WITH_AXIS_SCROLLBAR				*
 *	Hong 06/13/08 QA80-11694 ORIGIN_CRASH_WHEN_RESCALE_WITH_MULTIPLE_SCROLLBAR_EXIST
 *	Kyle 11/24/2008 QA80-12156-P1 UPDATE_RANGE_WHEN_GRAPH_SCALE_CHANGING		*
 *	Kyle 11/25/2008 QA80-12156-P2 UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT			*
 *	Kyle 12/01/2008 QA80-12156-P3 SUPPORT_RESCALE_THE_OTHER_AXIS				*
 *	CPY 12/6/06 QA70-12736 LT_NEED_MORE_CNTRL_ON_ALLOWING_OC_FUNCS				*
 *	Kyle 12/18/2008 QA80-12156-P8 v8.0988 SET_SCROLLBAR_AND_SCROLLTHUMB_ATTACH_TO_LAYER
 *	Hong 01/05/09 v8.0993d FIX_AXISSCROLLBAR_DEATH_LOOP_SHEN_PLOT_EMPTY_PCLAMP	*
 *	Kyle 02/17/2009 QA80-12156-P9 UPDATE_RANGE_DIRECTION_ON_SCALE_CHANGE		*
 *	Kyle 04/28/2009 FIX_ENDLESS_REFRESH_IN_OLD_PROJECT							*
 *	Kyle 12/07/2009 QA80-14788 AXIS_SCROLLBAR_NEEDS_DELETE_ITEM_IN_RIGHT_CLICK_MENU
 *------------------------------------------------------------------------------*/
 
#include <Origin.h>
#include <Control.h>
#include "OriginEvents.h"
#include "grobj_utils.h"

#define		NUM_ZOOM_FACTOR				20
#define		SCROLLBAR_RANGE				"Scrollbar.Range"

/// Hong 03/23/07 V8.0588 ALLOW_DELETE_SCROLLBAR
#define STATE_SCROLL_BAR GOC_NO_STATE|GOC_NO_SELECT
#define STATE_SCROLL_THUMB GOC_NO_ROTATE|GOC_NO_SKEW|GOC_NO_EDIT|GOC_REV_USER_DEL
/// end ALLOW_DELETE_SCROLLBAR
//int nAttach = 1 page


///Kyle 04/28/2009 FIX_ENDLESS_REFRESH_IN_OLD_PROJECT
// to make sure left <= right and top <= bottom
static void _check_object_rect(FRECT & fr)
{
	if(fr.left > fr.right)
	{
		double dTemp = fr.left;
		fr.left = fr.right;
		fr.right = dTemp;
	}
	if(fr.top > fr.bottom)
	{
		double dTemp = fr.top;
		fr.top = fr.bottom;
		fr.bottom = dTemp;
	}
}
///End FIX_ENDLESS_REFRESH_IN_OLD_PROJECT

static bool _set_scrobar_size(GraphObject& go, FRECT* pfr)
{
	if(NULL == pfr)
		return false;
	
	Tree tr;
	vector vx(4), vy(4);
	vx[0] = vx[3] = pfr->left;
	vy[0] = vy[1] = pfr->top;
	vx[2] = vx[1] = pfr->right;
	vy[3] = vy[2] = pfr->bottom;
	tr.Root.Data.X.dVals = vx;
	tr.Root.Data.Y.dVals = vy;
	
	int iRet = go.UpdateThemeIDs(tr.Root);
	if( iRet )
	      return false;
	return go.ApplyFormat(tr, true, true);
	
	
}
static bool _init_scrobar_rect(GraphObject& go, FRECT* pfr, int nStates, int nPattern, int nDirection, LPCSTR lpcszLT = NULL, int nEvent = GRCT_NONE, int nAttach = 1)
{
	go.SetEventHandler("ScrollbarEvents");	/// RVD 1/23/2007 SCROLLBAR_CONTEXT_MENU
	
	Tree tr;
	tr.Root.Fill.Color.nVal = RGB2OCOLOR(0x00c8d0d4);
	tr.Root.Fill.Pattern.Style.nVal = nPattern;
	tr.Root.Fill.Pattern.PatternColor.nVal = RGB2OCOLOR(0x00FFFFFF);
	tr.Root.States.nVal = nStates;
	tr.Root.Direction.nVal = nDirection;
	tr.Root.Event.nVal = nEvent;
	if(lpcszLT)
	{
		tr.Root.Script.strVal = lpcszLT;
	}
	tr.Root.Dimension.Attachment.nVal = nAttach;
	int iRet = go.UpdateThemeIDs(tr.Root);
	if( iRet )
	      return false;
	if( !go.ApplyFormat(tr, true, true) )
		ASSERT(FALSE);
	
	return _set_scrobar_size(go, pfr);	
}

static void _set_vertical_lines(GraphLayer& gl, double x1, double x2, bool bShow, bool bHorizontal = true)
{
	vector 	vPos;
	vPos.Add(x1);
	vPos.Add(x2);
	gl.SetMarkerLines(vPos, bShow, bHorizontal);
}


/// Hong 01/30/07 SCROLLBAR_RECT_UPDATE_EVENT
class AxisScrollbar
{
public:
	AxisScrollbar()
	{
	}
	
	AxisScrollbar(double dBarX1, double dBarX2, double dDataX1, double dDataX2)
	{
		m_dBarX1 = dBarX1;
		m_dBarX2 = dBarX2;
		m_dDataX1 = m_dDataX1;
		m_dDataX2 = m_dDataX2;
	}
	~AxisScrollbar(){}
	
public:
	///Kyle 11/24/2008 QA80-12156-P1 UPDATE_RANGE_WHEN_GRAPH_SCALE_CHANGING
	void ExtendRange(GraphLayer& gl, LPCSTR lpcszObjName, bool bHorizontal)
	{
		if(!gl)
		{
			error_report("Invalid GraphLayer in ResetRangeInfo");
			return;
		}
		bool bNeedUpdate = false;
		GraphObject goThumb;
		Tree trRange;
		info_get_section(gl, trRange, SCROLLBAR_RANGE);
		goThumb = gl.GraphObjects(X_SCROLL_THUMB_NAME);
		if(goThumb)
		{
			double 	x1 = gl.X.From,
					x2 = gl.X.To;
			///Kyle 02/17/2009 QA80-12156-P9 UPDATE_RANGE_DIRECTION_ON_SCALE_CHANGE
			if((x2 - x1) * (trRange.X2.dVal - trRange.X1.dVal) < 0)
			{
				bNeedUpdate = true;
				double dX1 = trRange.X1.dVal;
				trRange.X1.dVal = trRange.X2.dVal;
				trRange.X2.dVal = dX1;

				double dX01 = trRange.X01.dVal;
				trRange.X01.dVal = trRange.X02.dVal;
				trRange.X02.dVal = dX01;
				
				trRange.XMargin.dVal = -trRange.XMargin.dVal;
			}
			///End UPDATE_RANGE_DIRECTION_ON_SCALE_CHANGE

			double 	dLeft 	= 	trRange.X1.dVal + trRange.XMargin.dVal,
					dRight 	= 	trRange.X2.dVal - trRange.XMargin.dVal;
			if(	x2 > x1 && x1 < dLeft ||
				x2 < x1 && x1 > dLeft )
			{
				bNeedUpdate = true;
				dLeft = x1;
			}
			if(	x2 > x1 && dRight < x2 ||
				x2 < x1 && dRight > x2 )
			{
				bNeedUpdate = true;
				dRight = x2;
			}
			if(bNeedUpdate)
			{
				trRange.XMargin.dVal = 0.05 * (dRight - dLeft);
				trRange.X1.dVal = dLeft - trRange.XMargin.dVal;
				trRange.X2.dVal = dRight + trRange.XMargin.dVal;
			}
		}
		goThumb = gl.GraphObjects(Y_SCROLL_THUMB_NAME);
		if(goThumb)
		{
			bNeedUpdate = true;
			double 	y1 = gl.Y.From,
					y2 = gl.Y.To;
			///Kyle 02/17/2009 QA80-12156-P9 UPDATE_RANGE_DIRECTION_ON_SCALE_CHANGE
			if((y2-y1) * (trRange.Y2.dVal - trRange.Y1.dVal) < 0)
			{
				bNeedUpdate = true;
				double dY1 = trRange.Y1.dVal;
				trRange.Y1.dVal = trRange.Y2.dVal;
				trRange.Y2.dVal = dY1;
				
				double dY01 = trRange.Y01.dVal;
				trRange.Y01.dVal = trRange.Y02.dVal;
				trRange.Y02.dVal = dY01;
				
				trRange.XMargin.dVal = -trRange.XMargin.dVal;
			}
			///End UPDATE_RANGE_DIRECTION_ON_SCALE_CHANGE

			double 	dBottom = 	trRange.Y1.dVal + trRange.XMargin.dVal,
					dTop 	= 	trRange.Y2.dVal - trRange.XMargin.dVal;
			if(	y2 > y1 && y1 < dBottom ||
				y2 < y1 && y1 > dBottom )
			{
				bNeedUpdate = true;
				dBottom = y1;
			}
			if(	y2 > y1 && dTop < y2 ||
				y2 < y1 && dTop > y2 )
			{
				bNeedUpdate = true;
				dTop = y2;
			}
			if(bNeedUpdate)
			{
				trRange.XMargin.dVal = 0.05 * (dTop - dBottom);
				trRange.Y1.dVal = dBottom - trRange.XMargin.dVal;
				trRange.Y2.dVal = dTop + trRange.XMargin.dVal;
			}
		}
		if(bNeedUpdate)
		{
			info_set_section(gl, trRange, SCROLLBAR_RANGE);
			///Kyle 04/28/2009 FIX_ENDLESS_REFRESH_IN_OLD_PROJECT
			//Update(gl, lpcszObjName, bHorizontal, false);
			GraphObject goThumb = gl.GraphObjects(lpcszObjName);
			if(goThumb)
			{
				int nThumbUID = goThumb.GetUID();
				if(nThumbUID == m_nThumbUID)
					Update(gl, lpcszObjName, bHorizontal, false);
			}
			///End FIX_ENDLESS_REFRESH_IN_OLD_PROJECT
		}
	}
	///End UPDATE_RANGE_WHEN_GRAPH_SCALE_CHANGING
	///Kyle 11/25/2008 QA80-12156-P2 UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT
	void UpdateOnChange(GraphLayer& gl, LPCSTR lpcszObjName, bool bHorizontal)
	{
		if(!gl)
			return;
		GraphObject goThumb = gl.GraphObjects(lpcszObjName);
		if(!goThumb || m_nThumbUID != goThumb.GetUID())
			return;

		double dFrom, dTo;
		if(bHorizontal)
		{
			dFrom = gl.X.From;
			dTo = gl.X.To;
		}
		else
		{
			dFrom = gl.Y.From;
			dTo = gl.Y.To;
		}
		/// Hong 01/05/09 v8.0993d FIX_AXISSCROLLBAR_DEATH_LOOP_SHEN_PLOT_EMPTY_PCLAMP
		//double min_scale_span = min_scale_threshold * ( m_dDataX2 - m_dDataX1 );
		double min_scale_span = fabs(min_scale_threshold * ( m_dDataX2 - m_dDataX1 ));
		/// end FIX_AXISSCROLLBAR_DEATH_LOOP_SHEN_PLOT_EMPTY_PCLAMP
		if(fabs(m_dLastFrom - dFrom)>min_scale_span || fabs(m_dLastTo - dTo)>min_scale_span)
		{
			if(m_goThumb)
				m_goThumb.PostMessage(OE_SCALE_CHANGE);		// to update thumb
			return;
		}

		calculateThumbPosition(dFrom, dTo);
		if(fabs(m_dLastFrom - dFrom)>min_scale_span || fabs(m_dLastTo - dTo)>min_scale_span)
		{
			if(m_goThumb)
				m_goThumb.PostMessage(OE_MOVE);				// to update layer
			return;
		}
	}
	///End UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT

	/// Hong 06/05/07 QA80-9286-P10 FIX_THUMB_SIZE_NOT_CORRECT_AFTER_MOVED
	//void UpdateLayer()
	void UpdateLayer(bool bRescale = true)
	/// end FIX_THUMB_SIZE_NOT_CORRECT_AFTER_MOVED
	{
		if(!m_goThumb)
		{
			error_report("Found invalid Thumb object in UpdateLayer");
			return;
		}
		
		double 	dx1, dx2;
		calculateThumbPosition(dx1, dx2);
		///Kyle 11/25/2008 QA80-12156-P2 UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT
		GraphLayer gl;
		m_goThumb.GetParent(gl);
		double dLayerLastFrom, dLayerLastTo;
		if(m_bHorizontal)
		{
			dLayerLastFrom = gl.X.From;
			dLayerLastTo = gl.X.To;
		}
		else
		{
			dLayerLastFrom = gl.Y.From;
			dLayerLastTo = gl.Y.To;
		}
		/// Hong 01/05/09 v8.0993d FIX_AXISSCROLLBAR_DEATH_LOOP_SHEN_PLOT_EMPTY_PCLAMP
		//double min_scale_span = min_scale_threshold * ( m_dDataX2 - m_dDataX1 );
		double min_scale_span = fabs(min_scale_threshold * ( m_dDataX2 - m_dDataX1 ));
		/// end FIX_AXISSCROLLBAR_DEATH_LOOP_SHEN_PLOT_EMPTY_PCLAMP
		if( fabs(dx1 - dLayerLastFrom) < min_scale_span && fabs(dx2 - dLayerLastTo) < min_scale_span )		// not move
			return;
		m_dLastFrom = dx1;
		m_dLastTo = dx2;
		///End UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT
		/// Hong 03/29/07 v8.0592 ADD_MIN_THUMB_RESTRICTION
		if ( bRescale ) // Hong 06/05/07 QA80-9286-P10 FIX_THUMB_SIZE_NOT_CORRECT_AFTER_MOVED
			UpdateThumb(dx1, dx2);
		/// end ADD_MIN_THUMB_RESTRICTION
		///Kyle 11/25/2008 QA80-12156-P2 UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT
		//GraphLayer gl;
		//m_goThumb.GetParent(gl);
		///End UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT
		if(m_bHorizontal)
		{
			gl.X.From = dx1;
			gl.X.To = dx2;
			/// Hong 03/27/07 v8.0590 QA80-9286-P9 FIX_Y_SCROLLBAR_FAIL_UPDATE_LINK
			LT_execute("x1=x1"); //force update X axis
			/// end FIX_Y_SCROLLBAR_FAIL_UPDATE_LINK
		}
		else
		{
			gl.Y.From = dx1;
			gl.Y.To = dx2;
			/// Hong 03/27/07 v8.0590 QA80-9286-P9 FIX_Y_SCROLLBAR_FAIL_UPDATE_LINK
			LT_execute("y1=y1"); //force update Y axis
			/// end FIX_Y_SCROLLBAR_FAIL_UPDATE_LINK
		}
		// force refresh layer, not know why auto refresh not work after change X/Y
		/*
		GraphPage gp;
		m_activeGL.GetParent(gp);
		gp.Refresh();
		*/
		//gl.LT_execute("x1=x1"); /// Hong 03/27/07 v8.0590 QA80-9286-P9 FIX_Y_SCROLLBAR_FAIL_UPDATE_LINK

		RescaleTheOtherAxis();			///Kyle 12/01/2008 QA80-12156-P3 SUPPORT_RESCALE_THE_OTHER_AXIS
	}
	///Kyle 11/24/2008 QA80-12156-P1 UPDATE_RANGE_WHEN_GRAPH_SCALE_CHANGING
	//void Update(GraphLayer& gl, LPCSTR lpcszObjName, bool bHorizontal)
	void Update(GraphLayer& gl, LPCSTR lpcszObjName, bool bHorizontal, bool bShowThumbPositions = true)
	///End UPDATE_RANGE_WHEN_GRAPH_SCALE_CHANGING
	{	
		if(!gl)
		{
			error_report("Invalid GraphLayer in Update");
			return;
		}	
		
		m_goThumb = gl.GraphObjects(lpcszObjName);
		if(!m_goThumb)
		{
			error_report("Found invalid Thumb object in Update");
			return;
		}		
		m_bHorizontal = bHorizontal;
		
		///Kyle 11/25/2008 QA80-12156-P2 UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT
		m_nThumbUID = m_goThumb.GetUID();
		if(m_bHorizontal)
		{
			m_dLastFrom = gl.X.From;
			m_dLastTo = gl.X.To;
		}
		else
		{
			m_dLastFrom = gl.Y.From;
			m_dLastTo = gl.Y.To;
		}
		///End UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT
		
		FRECT 			fr;		
		GraphObject 	grBar;
		if(find_connected_object(m_goThumb, grBar) && get_go_rect(grBar, fr))
		{
			///Kyle 04/28/2009 FIX_ENDLESS_REFRESH_IN_OLD_PROJECT
			_check_object_rect(fr);
			///End FIX_ENDLESS_REFRESH_IN_OLD_PROJECT
			if( m_bHorizontal )
			{
				m_dBarX1 = fr.left;
				m_dBarX2 = fr.right;
			}
			else
			{
				/// Hong 03/07/07 QA80-9286-P7 FIX_ERROR_POSITION_FOR_VERTICAL_THUMB_LINE_WHEN_MOVING
				//m_dBarX1 = fr.top;
				//m_dBarX2 = fr.bottom;
				///Kyle 04/28/2009 FIX_ENDLESS_REFRESH_IN_OLD_PROJECT, For graph 0 means the bottom side but for the rect it means the top side
				//m_dBarX2 = fr.top;
				//m_dBarX1 = fr.bottom;
				m_dBarX2 = 1 - fr.top;
				m_dBarX1 = 1 - fr.bottom;
				///End FIX_ENDLESS_REFRESH_IN_OLD_PROJECT
				/// end FIX_ERROR_POSITION_FOR_VERTICAL_THUMB_LINE_WHEN_MOVING
			}
			
			getRangeInfo(gl);//get data range info from GraphLayer info to data member m_dDataX1, m_dDataX2......	
			
			// deal with the case that layer scale was changed before loading the setting but the thumb not updated
			UpdateThumb(m_dLastFrom, m_dLastTo);			///Kyle 12/01/2008 QA80-12156-P3 SUPPORT_RESCALE_THE_OTHER_AXIS
			
			if(bShowThumbPositions)		///Kyle 11/24/2008 QA80-12156-P1 UPDATE_RANGE_WHEN_GRAPH_SCALE_CHANGING
				ShowThumbPositions();
		}
	}
	
	void SaveSettings()
	{
		if(!m_goThumb)
		{
			error_report("Found invalid Thumb object in SaveSettings");
			return;
		}
		
		ShowThumbLines(false); // hiddden thumb lines	
		
		setRangeInfo();
	}
	


	void ShowThumbLines(bool bShow)
	{
		if(!m_goThumb)
		{
			error_report("Found invalid Thumb object in ShowThumbLinesPositions");
			return;
		}
		
		GraphLayer gl;
		m_goThumb.GetParent(gl);
		
	 	int		numLines = 2;	
		for(int ii=0; ii<numLines; ii++)
		{
			gl.SetShowMarkerLine(bShow, ii, m_bHorizontal);
		}	
	}

	void ShowThumbLinesPositions(double x1, double x2)
	{
		if(!m_goThumb)
		{
			error_report("Found invalid Thumb object in ShowThumbLinesPositions");
			return;
		}
		
		GraphLayer gl;
		m_goThumb.GetParent(gl);
		//---- CPY 2/23/2007 AXIS_SCROLLBAR_NEEDS_TO_WORK_FROM_LOADING_OPJ
		//gl.MoveMarkerLine(x1, 0, m_bHorizontal);
		//gl.MoveMarkerLine(x2, 1, m_bHorizontal);
		//ShowThumbLines(true);
		_set_vertical_lines(gl, x1, x2, true, m_bHorizontal);
		//---
	}
	
	void ShowThumbPositions()
	{
		if(!m_goThumb)
		{
			error_report("Found invalid Thumb object in ShowThumbPositions");
			return;
		}
		
		double dx1, dx2;
		if(calculateThumbPosition(dx1, dx2))
		{
			string 	str;
			str.Format("X1 = %g, X2 = %g", dx1, dx2);
			SetStatusBarText(str);
			
			ShowThumbLinesPositions(dx1, dx2);
		}	
	}
	///Kyle 12/01/2008 QA80-12156-P3 SUPPORT_RESCALE_THE_OTHER_AXIS
	bool IsHorizontal()
	{
		return m_bHorizontal;
	}
	bool IsAutoRescale()
	{
		return m_bAutoRescale;
	}
	void SetAutoRescale(bool AutoRescale = true)
	{
		m_bAutoRescale = AutoRescale;
		setRangeInfo();
	}
	bool RescaleTheOtherAxis()
	{
		if(!m_goThumb)
			return error_report("Found invalid Thumb object in RescaleTheOtherAxis");	
		if(!m_bHorizontal || !m_bAutoRescale)	// only support auto rescaling y from x
			return false;
		GraphLayer gl;
		m_goThumb.GetParent(gl);
		return gl.Rescale(OKAXISTYPE_X | ANL_USE_DATA_IN_XRANGE);
	}
	///End SUPPORT_RESCALE_THE_OTHER_AXIS
	//---- CPY 4/29/07 SEPARATE_ZOOM_SCROLL_RANGE_AND_AXIS_RANGE
	bool ZoomScrollRange(bool bIn, double& x1, double& x2)
	{
		if(!m_goThumb)
			return error_report("Found invalid Thumb object in ZoomInOut");	
		GraphLayer gl;
		m_goThumb.GetParent(gl);
		if(m_bHorizontal)
			x1 = gl.X.From, x2 = gl.X.To;
		else
			x1 = gl.Y.From, x2 = gl.Y.To;

		double s1, s2;
		if(bIn) // use current axis scale and expand it 2 times as the new scroll range
		{
			///Kyle 11/25/2008 QA80-12156-P2 UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT
			//double dRange = x2 - x1;
			//double dMiddle = (x2 + x1) / 2;
			//s1 = dMiddle - dRange * 2;
			//s2 = dMiddle + dRange * 2;	
			FRECT fr;
			m_goThumb.GetTempBoundingBox(&fr);
			///Kyle 04/28/2009 FIX_ENDLESS_REFRESH_IN_OLD_PROJECT
			_check_object_rect(fr);
			///End FIX_ENDLESS_REFRESH_IN_OLD_PROJECT

			double dRect = m_bHorizontal? fr.right - fr.left : fr.bottom - fr.top;
			if(dRect/2.0 < min_thumb)	// rect after update
				return false;
			double dRange = m_dDataX2 - m_dDataX1;
			s1 = m_dDataX1 - dRange/2.0;
			s2 = m_dDataX2 + dRange/2.0;
			///End UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT
		}
		else // use old scroll range and expand that by 1/4 in both direction
		{
			double dRange = m_dDataX2 - m_dDataX1;
			///Kyle 11/25/2008 QA80-12156-P2 UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT
			//s1 = m_dDataX1 - dRange/4.;
			//s2 = m_dDataX2 + dRange/4.;
			s1 = m_dDataX1 + dRange/4.;
			s2 = m_dDataX2 - dRange/4.;	
			if(m_dXMargin > m_dDataX01 - s1)
				s1 = m_dDataX01 - m_dXMargin;
			if(m_dXMargin > s2 - m_dDataX02)
				s2 = m_dDataX02 + m_dXMargin;
			///End UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT
		}
		m_dDataX1 = s1;
		m_dDataX2 = s2;
		setRangeInfo();
		return true;
	}
	//----
	//CPY zoom int/out current axis scale range, keeping scroll range unchanged
	bool ZoomInOut(bool bIn, double& x1, double& x2)
	{
		if(!m_goThumb)
			return error_report("Found invalid Thumb object in ZoomInOut");		
		
		//---- CPY 2/23/2007 AXIS_SCROLL_BAR_ZOOM_IN_SHOULD_USE_CURRENT_THUMB_POSITION
		/*
		double dRange = m_dDataX2 - m_dDataX1;
		double dMiddle = (m_dDataX2 + m_dDataX1) / 2;
		if( bIn )
			dRange = dRange * (100 - NUM_ZOOM_FACTOR) / 100;
		else
			dRange = dRange * (100 + NUM_ZOOM_FACTOR) / 100 ;		
		m_dDataX1 = dMiddle - dRange / 2;
		m_dDataX2 = dMiddle + dRange / 2;	
		*/
		GraphLayer gl;
		m_goThumb.GetParent(gl);
		if(m_bHorizontal)
			x1 = gl.X.From, x2 = gl.X.To;
		else
			x1 = gl.Y.From, x2 = gl.Y.To;
		
		double dRange = x2 - x1;
		double dMiddle = (x2 + x1) / 2;
		
		if( bIn )
			dRange = dRange / 2;
		else
			dRange = dRange * 2;
		//----
		/// Hong 03/09/07 FIX_ZOOM_MENU_FAIL_TO_WORK
		// this fix restrict zoom to do as auto resize
		//m_dDataX1 = dMiddle - dRange * 2;
		//m_dDataX2 = dMiddle + dRange * 2;	
		x1 = dMiddle - dRange / 2;
		x2 = dMiddle + dRange / 2;	
		/// end FIX_ZOOM_MENU_FAIL_TO_WORK
		setRangeInfo(); //set data range info from data member m_dDataX1, m_dDataX2 back to GraphLayer info......		
		
		return true;
	}
	
	///Kyle 11/24/2008 QA80-12156-P1 UPDATE_RANGE_WHEN_GRAPH_SCALE_CHANGING
	bool UpdateThumb(GraphLayer& gl)
	{
		if(!gl)
			return false;
		double dStart, dEnd;
		if(m_bHorizontal)
		{
			dStart = gl.X.From;
			dEnd = gl.X.To;
		}
		else
		{
			dStart = gl.Y.From;
			dEnd = gl.Y.To;
		}
		return UpdateThumb(dStart, dEnd);
	}
	///End UPDATE_RANGE_WHEN_GRAPH_SCALE_CHANGING
		
	bool UpdateThumb(double dStart, double dEnd)
	{
		if(!m_goThumb)
			return error_report("Found invalid Thumb object in UpdateThumb");
		
		///Kyle 11/25/2008 QA80-12156-P2 UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT
		m_dLastFrom = dStart;
		m_dLastTo = dEnd;
		///End UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT

		double f1 = (dStart - m_dDataX1)/(m_dDataX2-m_dDataX1);
	    double f2 = (dEnd - m_dDataX1)/(m_dDataX2-m_dDataX1);    
	    
	    if(f1 < 0 || f1 > 1) f1 = 0;
	    if(f2 <0 || f2 > 1 || f2 < f1) f2 = 1;
	    
	    double thumbX1 = m_dBarX1 + f1*(m_dBarX2 - m_dBarX1);
	    double thumbX2 = m_dBarX1 + f2*(m_dBarX2 - m_dBarX1);
	    
		
		FRECT 	frThumb;
		if( !m_goThumb.GetTempBoundingBox(&frThumb) )
			return false;	

		///Kyle 04/28/2009 FIX_ENDLESS_REFRESH_IN_OLD_PROJECT
		_check_object_rect(frThumb);
		///End FIX_ENDLESS_REFRESH_IN_OLD_PROJECT

			
		if( m_bHorizontal )
		{
			frThumb.left = thumbX1;
			frThumb.right = thumbX2;
		}
		else
		{
			/// Hong 03/07/07 QA80-9286-P7 FIX_ERROR_POSITION_FOR_VERTICAL_THUMB_LINE_WHEN_MOVING
			//frThumb.top = thumbX1;
			//frThumb.bottom = thumbX2;
			///Kyle 04/28/2009 FIX_ENDLESS_REFRESH_IN_OLD_PROJECT, For graph 0 means the bottom side but for the rect it means the top side
			//frThumb.top = thumbX2;
			//frThumb.bottom = thumbX1;
			frThumb.top = 1 - thumbX2;
			frThumb.bottom = 1 - thumbX1;
			///End FIX_ENDLESS_REFRESH_IN_OLD_PROJECT
			/// end FIX_ERROR_POSITION_FOR_VERTICAL_THUMB_LINE_WHEN_MOVING
		}
		
		Tree 	tr;
		tr = m_goThumb.GetFormat(FPB_ALL, FOB_ALL, TRUE, TRUE);	
		string script = tr.Root.Script.strVal;	
		//if(!_init_scrobar_rect(m_goThumb, &frThumb, GOC_NO_ROTATE|GOC_NO_SKEW|GOC_NO_EDIT, 0 /*none*/, m_bHorizontal ? LINEDIR_VERTICAL : LINEDIR_HORIZONTAL, script, GRCT_ANY_EVENT))//GRCT_ANY_EVENT, GRCT_SIZEMOVE))
		if(!_set_scrobar_size(m_goThumb, &frThumb))
			return false;

		return true;
	}

	// Keep the From & To of Thumb and Zoom In/Out the From&To of Bar, and then resize Thumb
	//----- CPY 4/29/07 SEPARATE_ZOOM_SCROLL_RANGE_AND_AXIS_RANGE
	//bool OnZoomInOut(GraphObject &grThumb, bool bIn)
	bool OnZoomInOut(GraphObject &grThumb, bool bIn, bool bScrollrange = false)
	//-----
	{
		if(!m_goThumb)
			return error_report("Found invalid Thumb object in OnZoomInOut");		
		//---- CPY 2/23/2007 AXIS_SCROLL_BAR_ZOOM_IN_SHOULD_USE_CURRENT_THUMB_POSITION
		//// get the From & To for Thumb.
		//double 	ax1, ax2;
		//calculateThumbPosition(ax1, ax2);	
		//ZoomInOut(bIn);	
		//if(ax1 < m_dDataX1)
			//ax1 = m_dDataX1;
		//if(ax2 > m_dDataX2)
			//ax2 = m_dDataX2;
		LT_execute("page -s");
		double 	ax1, ax2;
		//----- CPY 4/29/07 SEPARATE_ZOOM_SCROLL_RANGE_AND_AXIS_RANGE
		//ZoomInOut(bIn, ax1, ax2);
		//UpdateThumb(ax1, ax2);
		//UpdateLayer();
		if(bScrollrange)
		{
			ZoomScrollRange(bIn, ax1, ax2);
			UpdateThumb(ax1, ax2);
		}
		else
		{
			ZoomInOut(bIn, ax1, ax2);
			UpdateThumb(ax1, ax2);
			UpdateLayer();
		}
		//-----
		return true;
	}

	bool Reset()
	{
		if(!m_goThumb)
			return error_report("Found invalid Thumb object in Reset");		
		/// Hong 03/09/07 FIX_ZOOM_MENU_FAIL_TO_WORK
		//m_dDataX1 = m_dDataX01;
		//m_dDataX2 = m_dDataX02;
		LT_execute("page -s");
		//---- CPY 4/29/07 SEPARATE_ZOOM_SCROLL_RANGE_AND_AXIS_RANGE
		m_dDataX1 = m_dDataX01 - m_dXMargin;
		m_dDataX2 = m_dDataX02 + m_dXMargin;
		//----
		UpdateThumb(m_dDataX01, m_dDataX02);
		/// end FIX_ZOOM_MENU_FAIL_TO_WORK
		UpdateLayer();
		
		setRangeInfo();		
		return true;
	}
	
	///Kyle 12/07/2009 QA80-14788 AXIS_SCROLLBAR_NEEDS_DELETE_ITEM_IN_RIGHT_CLICK_MENU
	bool Delete()
	{
		if(!m_goThumb)
			return error_report("Found invalid Thumb object in Delete");

		ShowThumbLines(false);

		GraphObject 	grBar;
		find_connected_object(m_goThumb, grBar);
		if(grBar)
			grBar.Destroy();
		m_goThumb.Destroy();
		
		return true;
	}
	///End AXIS_SCROLLBAR_NEEDS_DELETE_ITEM_IN_RIGHT_CLICK_MENU
	
private:
	bool calculateThumbPosition(double& dStart, double& dEnd)
	{
		if(!m_goThumb)
			return error_report("Found invalid Thumb object in calculateThumbPosition");		
		
		FRECT fr;
		if(m_dBarX2 != m_dBarX1 && m_goThumb.GetTempBoundingBox(&fr))
		{
			///Kyle 04/28/2009 FIX_ENDLESS_REFRESH_IN_OLD_PROJECT
			_check_object_rect(fr);
			///End FIX_ENDLESS_REFRESH_IN_OLD_PROJECT

			double f1, f2;
			if( m_bHorizontal )
			{
				/// Hong 03/29/07 v8.0592 ADD_MIN_THUMB_RESTRICTION
				if ( fr.right - fr.left < min_thumb)
					fr.left = fr.right - min_thumb;
				/// end ADD_MIN_THUMB_RESTRICTION
				f1 = (fr.left - m_dBarX1)/(m_dBarX2 - m_dBarX1);
				f2 = (fr.right - m_dBarX1)/(m_dBarX2 - m_dBarX1);
			}	
			else
			{
				/// Hong 03/29/07 v8.0592 ADD_MIN_THUMB_RESTRICTION
				if ( fr.bottom - fr.top < min_thumb)
					fr.top = fr.bottom - min_thumb;
				/// end ADD_MIN_THUMB_RESTRICTION
				/// Hong 03/07/07 QA80-9286-P7 FIX_ERROR_POSITION_FOR_VERTICAL_THUMB_LINE_WHEN_MOVING
				//f1 = (fr.top - m_dBarX1)/(m_dBarX2 - m_dBarX1);
				//f2 = (fr.bottom - m_dBarX1)/(m_dBarX2 - m_dBarX1);
				///Kyle 04/28/2009 FIX_ENDLESS_REFRESH_IN_OLD_PROJECT
				//f1 = (fr.bottom - m_dBarX1)/(m_dBarX2 - m_dBarX1);
				//f2 = (fr.top - m_dBarX1)/(m_dBarX2 - m_dBarX1);
				f1 = (1 - fr.bottom - m_dBarX1)/(m_dBarX2 - m_dBarX1);
				f2 = (1 - fr.top - m_dBarX1)/(m_dBarX2 - m_dBarX1);
				///End FIX_ENDLESS_REFRESH_IN_OLD_PROJECT
				/// end FIX_ERROR_POSITION_FOR_VERTICAL_THUMB_LINE_WHEN_MOVING
			}
			if(f1 < 0.02) f1 = 0;
			if(f2 > 0.98) f2 = 1;
			
			dStart = m_dDataX1 + f1 * (m_dDataX2 - m_dDataX1);
			dEnd = m_dDataX1 + f2 * (m_dDataX2 - m_dDataX1);
			
			return true;
		}
		return false;
	}	
	
	void getRangeInfo(GraphLayer& gl)
	{
		if(!gl || !m_goThumb)
		{
			error_report("Found invalid Thumb object in getRangeInfo");
			return;
		}	
		
		Tree trRange;
		info_get_section(gl, trRange, SCROLLBAR_RANGE);
		
		if( m_bHorizontal )	
		{
			m_dDataX1 = trRange.X1.dVal;
			m_dDataX2 = trRange.X2.dVal;
			m_dDataX01 = trRange.X01.dVal;
			m_dDataX02 = trRange.X02.dVal;
			m_bAutoRescale = trRange.XRescaleY ? trRange.XRescaleY.nVal : 0;;		///Kyle 12/01/2008 QA80-12156-P3 SUPPORT_RESCALE_THE_OTHER_AXIS
		}
		else
		{
			m_dDataX1 = trRange.Y1.dVal;
			m_dDataX2 = trRange.Y2.dVal;
			m_dDataX01 = trRange.Y01.dVal;
			m_dDataX02 = trRange.Y02.dVal;
			m_bAutoRescale = trRange.YRescaleX ? trRange.YRescaleX.nVal : 0;;		///Kyle 12/01/2008 QA80-12156-P3 SUPPORT_RESCALE_THE_OTHER_AXIS

		}
		//---- CPY 4/29/07 SEPARATE_ZOOM_SCROLL_RANGE_AND_AXIS_RANGE
		m_dXMargin = trRange.XMargin.dVal;
		//-----
	}
	
	void setRangeInfo()
	{
		if(!m_goThumb)
		{
			error_report("Found invalid Thumb object in getRangeInfo");
			return;
		}
		
		GraphLayer gl;
		m_goThumb.GetParent(gl);
		
		Tree trRange;
		info_get_section(gl, trRange, SCROLLBAR_RANGE);
		
		if( m_bHorizontal )	
		{
			trRange.X1.dVal = m_dDataX1;
			trRange.X2.dVal = m_dDataX2;
			trRange.X01.dVal = m_dDataX01;
			trRange.X02.dVal = m_dDataX02;
			trRange.XRescaleY.nVal = m_bAutoRescale;		///Kyle 12/01/2008 QA80-12156-P3 SUPPORT_RESCALE_THE_OTHER_AXIS
		}
		else
		{
			trRange.Y1.dVal = m_dDataX1;
			trRange.Y2.dVal = m_dDataX2;
			trRange.Y01.dVal = m_dDataX01;
			trRange.Y02.dVal = m_dDataX02;
			trRange.YRescaleX.nVal = m_bAutoRescale;		///Kyle 12/01/2008 QA80-12156-P3 SUPPORT_RESCALE_THE_OTHER_AXIS
		}
		
		info_set_section(gl, trRange, SCROLLBAR_RANGE);
		
	}
	
	
private:
	///Kyle 11/25/2008 QA80-12156-P2 UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT
	double 		m_dLastFrom;
	double 		m_dLastTo;
	UINT		m_nThumbUID;
	///End UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT
	/// Hong 03/29/07 v8.0592 ADD_MIN_THUMB_RESTRICTION
	static const double min_thumb;// = 0.005;
	/// end ADD_MIN_THUMB_RESTRICTION
	double 		m_dBarX1;
	double 		m_dBarX2;
	
	// actual scrollbar scale ranges
	double 		m_dDataX1;
	double 		m_dDataX2;
	// original full data range, this is what we show the Axis scale when Reset/Init the bar
	double		m_dDataX01;
	double		m_dDataX02;
	//---- CPY 4/29/07 SEPARATE_ZOOM_SCROLL_RANGE_AND_AXIS_RANGE
	//backup scrollbar scale ranges on init scrollbar for reset
	double		m_dXMargin;
	//----
	GraphObject	m_goThumb;
	bool		m_bHorizontal;
	
	static const double min_scale_threshold;		///Kyle 11/25/2008 QA80-12156-P2 UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT
	
	bool m_bAutoRescale;			///Kyle 12/01/2008 QA80-12156-P3 SUPPORT_RESCALE_THE_OTHER_AXIS
};

/// Hong 03/29/07 v8.0592 ADD_MIN_THUMB_RESTRICTION
static const double AxisScrollbar::min_thumb = 0.005;
/// end ADD_MIN_THUMB_RESTRICTION
static AxisScrollbar 	s_asBar;
/// end SCROLLBAR_RECT_UPDATE_EVENT

///Kyle 11/25/2008 QA80-12156-P2 UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT
static const double AxisScrollbar::min_scale_threshold = 0.005;
///End UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT

///Kyle 12/07/2009 QA80-14788 AXIS_SCROLLBAR_NEEDS_DELETE_ITEM_IN_RIGHT_CLICK_MENU
/*
#define		SCROLLBAREVENTID_ZOOM_IN	1
#define		SCROLLBAREVENTID_ZOOM_OUT	2
#define		SCROLLBAREVENTID_RESET		3
#define		SCROLLBAREVENTID_BASE		1010
#define		SCROLLBAR_ZOOM_LEVELS		5

//----- CPY 4/29/07 SEPARATE_ZOOM_SCROLL_RANGE_AND_AXIS_RANGE
#define SCROLLBAREVENTID_ZOOM_SCROLLRANGE_IN	10
#define SCROLLBAREVENTID_ZOOM_SCROLLRANGE_OUT	11
//-----

///Kyle 12/01/2008 QA80-12156-P3 SUPPORT_RESCALE_THE_OTHER_AXIS
#define SCROLLBAREVENTID_RESCALE_THE_OTHER_AXIS 12
///End SUPPORT_RESCALE_THE_OTHER_AXIS
*/
enum
{
	SCROLLBAREVENTID_ZOOM_IN			 = 1,
	SCROLLBAREVENTID_ZOOM_OUT,
	SCROLLBAREVENTID_RESET,
	SCROLLBAREVENTID_ZOOM_SCROLLRANGE_IN,
	SCROLLBAREVENTID_ZOOM_SCROLLRANGE_OUT,
	SCROLLBAREVENTID_RESCALE_THE_OTHER_AXIS,
	SCROLLBAREVENTID_DELETE,
};
///End AXIS_SCROLLBAR_NEEDS_DELETE_ITEM_IN_RIGHT_CLICK_MENU

	
enum
{
	OE_MENU_ZOOM = -10,
		
};

class	ScrollbarMenu		:	public Menu
{
public:
	ScrollbarMenu(GraphObject& go)
	{
		m_grObject = go;
		//m_bZoom = FALSE; /// Iris 01/31/2007 CONTEXT_MENU_SUPPORT_ZOOM_IN_OUT
		
		//Tree 	tr;
		//tr = go.GetFormat(FPB_ALL, FOB_ALL, TRUE, TRUE);	
		//bool 	bHorizontal = tr.Root.Direction.nVal == LINEDIR_VERTICAL;
		//s_sbRect.SaveObjRange(bHorizontal);
		
		//int iZoom = axis_scrollbar_zoom(m_grObject, 0.0);	
		/// Iris 01/31/2007 CONTEXT_MENU_SUPPORT_ZOOM_IN_OUT
		//int iZoom = s_sbRect.axis_scrollbar_zoom(m_grObject, 0.0);			
		///end CENTRRLIZE_WITH_NEW_CLASS
		
		/// Iris 01/29/2007 CONTEXT_MENU_SUPPORT_ZOOM_IN_OUT
		/*
		for(int ii=SCROLLBAR_ZOOM_LEVELS; ii>0; ii--)
		{
			string str;
			str.Format("%d:1", ii);
			UINT nFlags = MF_STRING;
			if( iZoom == ii )
				nFlags |= MF_CHECKED;
			Add(str, OnScale, nFlags, SCROLLBAREVENTID_BASE + ii);
		}
		
		for(ii=2; ii<=SCROLLBAR_ZOOM_LEVELS; ii++)
		{
			string str;
			str.Format("1:%d", ii);
			UINT nFlags = MF_STRING;
			if( -iZoom == ii )
				nFlags |= MF_CHECKED;
			Add(str, OnScale, nFlags, SCROLLBAREVENTID_BASE - ii);
		}
		*/
		//------ CPY 4/29/07 SEPARATE_ZOOM_SCROLL_RANGE_AND_AXIS_RANGE
		/*
		Add("Zoom In", OnZoom, MF_STRING, SCROLLBAREVENTID_ZOOM_IN);		
		Add("Zoom Out", OnZoom, MF_STRING, SCROLLBAREVENTID_ZOOM_OUT);
		*/
		Add(_L("Zoom In Axis Range"), OnZoom, MF_STRING, SCROLLBAREVENTID_ZOOM_IN);		
		Add(_L("Zoom Out Axis Range"), OnZoom, MF_STRING, SCROLLBAREVENTID_ZOOM_OUT);
		Add(NULL, OnZoom, MF_SEPARATOR);		
		Add(_L("Zoom In Scroll Range"), OnZoom, MF_STRING, SCROLLBAREVENTID_ZOOM_SCROLLRANGE_IN);		
		Add(_L("Zoom Out Scroll Range"), OnZoom, MF_STRING, SCROLLBAREVENTID_ZOOM_SCROLLRANGE_OUT);		
		Add(NULL, OnZoom, MF_SEPARATOR);		
		///Kyle 12/01/2008 QA80-12156-P3 SUPPORT_RESCALE_THE_OTHER_AXIS
		if(s_asBar.IsHorizontal())		// only support auto rescaling y from x
		{
			string strLabel = _L("Auto Rescale Y Axis");
			Add(strLabel, OnZoom, s_asBar.IsAutoRescale() ? MF_CHECKED : MF_UNCHECKED, SCROLLBAREVENTID_RESCALE_THE_OTHER_AXIS);
			Add(NULL, OnZoom, MF_SEPARATOR);
		}
		///End SUPPORT_RESCALE_THE_OTHER_AXIS
		Add(_L("Reset"), OnZoom, MF_STRING, SCROLLBAREVENTID_RESET);
		///end CONTEXT_MENU_SUPPORT_ZOOM_IN_OUT
		
		Add(_L("Delete"), OnZoom, MF_STRING, SCROLLBAREVENTID_DELETE);			///Kyle 12/07/2009 QA80-14788 AXIS_SCROLLBAR_NEEDS_DELETE_ITEM_IN_RIGHT_CLICK_MENU
	}
	
	void	OnZoom(uint nCmd)
	{
		//m_bZoom = TRUE;	/// Iris 01/31/2007 CONTEXT_MENU_SUPPORT_ZOOM_IN_OUT
	}
	
	bool	Show(int x, int y)
	{
		int nCmd = 0;
		TrackPopupMenu(0, x, y, GetWindow(), &nCmd);
		
		/// Iris 01/29/2007 CONTEXT_MENU_SUPPORT_ZOOM_IN_OUT
		/*
		if( m_bZoom )
		{
			double dZoom = (int)nCmd - SCROLLBAREVENTID_BASE;
			axis_scrollbar_zoom(m_grObject, dZoom);
		}
		*/	
		if(SCROLLBAREVENTID_ZOOM_IN == nCmd || SCROLLBAREVENTID_ZOOM_OUT == nCmd)
		{				
			bool	bIn = SCROLLBAREVENTID_ZOOM_IN == nCmd? true : false;
			//axis_srcollbar_zoom_in_out(m_grObject, bIn);
			s_asBar.OnZoomInOut(m_grObject, bIn);
		}
		if(SCROLLBAREVENTID_RESET == nCmd)
		{
			s_asBar.Reset();
		}
		///end CONTEXT_MENU_SUPPORT_ZOOM_IN_OUT
		//----- CPY 4/29/07 SEPARATE_ZOOM_SCROLL_RANGE_AND_AXIS_RANGE
		else if(SCROLLBAREVENTID_ZOOM_SCROLLRANGE_IN == nCmd || SCROLLBAREVENTID_ZOOM_SCROLLRANGE_OUT == nCmd)
		{				
			bool	bIn = SCROLLBAREVENTID_ZOOM_SCROLLRANGE_IN == nCmd? true : false;
			s_asBar.OnZoomInOut(m_grObject, bIn, true);
		}
		//----- end SEPARATE_ZOOM_SCROLL_RANGE_AND_AXIS_RANGE			
		///Kyle 12/01/2008 QA80-12156-P3 SUPPORT_RESCALE_THE_OTHER_AXIS
		else if(SCROLLBAREVENTID_RESCALE_THE_OTHER_AXIS == nCmd)
		{
			s_asBar.SetAutoRescale(!s_asBar.IsAutoRescale());
			s_asBar.RescaleTheOtherAxis();
		}
		///End SUPPORT_RESCALE_THE_OTHER_AXIS
		///Kyle 12/07/2009 QA80-14788 AXIS_SCROLLBAR_NEEDS_DELETE_ITEM_IN_RIGHT_CLICK_MENU
		else if( nCmd == SCROLLBAREVENTID_DELETE )
		{
			s_asBar.Delete();
		}
		///End AXIS_SCROLLBAR_NEEDS_DELETE_ITEM_IN_RIGHT_CLICK_MENU
		return true;
	}
	
private:
	GraphObject		m_grObject;
	BOOL			m_bZoom;
};

class OC_REGISTERED ScrollbarEvents : public OriginEventsBase
{
public:
	virtual bool OnContextMenu(int x, int y, DWORD dwControl = 0)
	{
		ScrollbarMenu menu(m_grObject);
		return menu.Show(x, y);
	}
	
	virtual	bool SetObj(OriginObject& obj)
	{
		m_grObject = obj;
		
		if( m_grObject )
			return true;
		
		return false;
	}
	
protected:	
	GraphObject		m_grObject; 
};
/// end SCROLLBAR_CONTEXT_MENU


//------- CPY 1/6/2007
// this assume proper LT codes in graph_controls.ogs
// scrollbar rect will be called xScrollbar if bHorizontal, or yScrollbar if bHorizontal=false
// and it has a rect inside called xScrollThumb or yScrollThumb
/// Hong 03/23/07 v8.0588 MORE_OPTION_ALLOW_NOT_RESCALE_ON_INIT
//bool add_axis_scrollbar(GraphLayer& gl, double x1, double x2, double left, double top, double length, double width, bool bHorizontal)
bool add_axis_scrollbar(GraphLayer& gl, double x1, double x2, double left, double top, double length, double width, bool bHorizontal, bool bResetScale)
{
	if( !gl )
       	return false;
	
	///Kyle 12/01/2008 QA80-12156-P3 SUPPORT_RESCALE_THE_OTHER_AXIS, only show one scrollbar in one layer
	string strRectToDel, strThumbToDel;
	if(bHorizontal)
	{
		strRectToDel = Y_SCROLL_BAR_NAME;
		strThumbToDel = Y_SCROLL_THUMB_NAME;
	}
	else
	{
		strRectToDel = X_SCROLL_BAR_NAME;
		strThumbToDel = X_SCROLL_THUMB_NAME;
	}
	gl.RemoveGraphObject(strRectToDel);
	gl.RemoveGraphObject(strThumbToDel);
	///End SUPPORT_RESCALE_THE_OTHER_AXIS

	Tree trRange;
	info_get_section(gl, trRange, SCROLLBAR_RANGE);
	//-----CPY 4/29/07 SEPARATE_ZOOM_SCROLL_RANGE_AND_AXIS_RANGE
	/// RVD 1/23/2007 SCROLLBAR_CONTEXT_MENU
	//trRange.ZOOMX.dVal = 1;
	//trRange.ZOOMY.dVal = 1;
	/// end SCROLLBAR_CONTEXT_MENU
	//-----
	
	FRECT fr;
	fr.left = left;
	fr.top = top;
	string script;
	string strRect, strThumb;
	double ax1, ax2, Rectx1, Rectx2;
	double dXSpace = 0.05*(x2 - x1); // Hong 03/15/07 EXPAND_5_PERCENT_SPACE_TO_BAR_BY_INIT_INDICATE_SCROLL_THUMB
	if( bHorizontal )
	{
		fr.right = left + length;
		fr.bottom = top + width;
		script = "run.section(graph_controls, XScroll, %1)";
		strRect = X_SCROLL_BAR_NAME;
		strThumb = X_SCROLL_THUMB_NAME;
		/// Hong 03/15/07 EXPAND_5_PERCENT_SPACE_TO_BAR_BY_INIT_INDICATE_SCROLL_THUMB
		//trRange.X1.dVal = x1;
		//trRange.X2.dVal = x2;
		trRange.X1.dVal = x1 - dXSpace;
		trRange.X2.dVal = x2 + dXSpace;
		/// end EXPAND_5_PERCENT_SPACE_TO_BAR_BY_INIT_INDICATE_SCROLL_THUMB
		/// RVD 1/23/2007 SCROLLBAR_CONTEXT_MENU
		trRange.X01.dVal = x1;
		trRange.X02.dVal = x2;
		/// end SCROLLBAR_CONTEXT_MENU
		ax1 = gl.X.From;
		ax2 = gl.X.To;
		Rectx1 = left;
		Rectx2 = fr.right;
	}
	else
	{
		fr.right = left + width;
		fr.bottom = top + length;
		script = "run.section(graph_controls, YScroll, %1)";
		strRect = Y_SCROLL_BAR_NAME;
		strThumb = Y_SCROLL_THUMB_NAME;
		/// Hong 03/15/07 EXPAND_5_PERCENT_SPACE_TO_BAR_BY_INIT_INDICATE_SCROLL_THUMB
		//trRange.Y1.dVal = x1;
		//trRange.Y2.dVal = x2;
		trRange.Y1.dVal = x1 - dXSpace;
		trRange.Y2.dVal = x2 + dXSpace;
		/// end EXPAND_5_PERCENT_SPACE_TO_BAR_BY_INIT_INDICATE_SCROLL_THUMB
		/// RVD 1/23/2007 SCROLLBAR_CONTEXT_MENU
		trRange.Y01.dVal = x1;
		trRange.Y02.dVal = x2;
		/// end SCROLLBAR_CONTEXT_MENU
		ax1 = gl.Y.From;
		ax2 = gl.Y.To;
		Rectx1 = top;
		Rectx2 = fr.bottom;
		
	}
	//-----CPY 4/29/07 SEPARATE_ZOOM_SCROLL_RANGE_AND_AXIS_RANGE
	trRange.XMargin.dVal = dXSpace;
	//-----
	
	/// Hong 03/15/07 EXPAND_5_PERCENT_SPACE_TO_BAR_BY_INIT_INDICATE_SCROLL_THUMB
	FRECT frTemp;
	frTemp = fr;
	/// Hong 03/27/07 V8.0590 FIX_Y_AXIS_FAIL_ADD_SPACE_AS_X
	//double dBarSpace = 0.05*(frTemp.right - frTemp.left); 
	double dBarSpace;
	/// end FIX_Y_AXIS_FAIL_ADD_SPACE_AS_X
	if( bHorizontal )
	{	
		dBarSpace = 0.05*(frTemp.right - frTemp.left); /// Hong 03/27/07 V8.0590 FIX_Y_AXIS_FAIL_ADD_SPACE_AS_X
		frTemp.left -= dBarSpace;
		frTemp.right += dBarSpace;
	}
	else
	{
		dBarSpace = 0.05*(frTemp.bottom - frTemp.top); /// Hong 03/27/07 V8.0590 FIX_Y_AXIS_FAIL_ADD_SPACE_AS_X
		frTemp.top -= dBarSpace;
		frTemp.bottom += dBarSpace;
	}
	/// end EXPAND_5_PERCENT_SPACE_TO_BAR_BY_INIT_INDICATE_SCROLL_THUMB
	GraphObject grRect;
	grRect = gl.GraphObjects(strRect);
	if(grRect)
		/// Hong 03/08/07 UPDATE_POSTION_IF_ALREAY_EXISTING
		//_init_scrobar_rect(grRect, NULL, GOC_NO_STATE|GOC_NO_SELECT, 7 /*dense mesh*/, LINEDIR_NONE);
		/// Hong 03/23/07 V8.0588 ALLOW_DELETE_SCROLLBAR
		//_init_scrobar_rect(grRect, &frTemp, GOC_NO_STATE|GOC_NO_SELECT, 7 /*dense mesh*/, LINEDIR_NONE);
		_init_scrobar_rect(grRect, &frTemp, STATE_SCROLL_BAR, 7 /*dense mesh*/, LINEDIR_NONE);
		/// end ALLOW_DELETE_SCROLLBAR
		/// end UPDATE_POSTION_IF_ALREAY_EXISTING
	else
	{
		gl.RemoveGraphObject(strRect);
		grRect = gl.CreateGraphObject(GROT_RECT);
		/// Hong 03/23/07 V8.0588 ALLOW_DELETE_SCROLLBAR
		//if(!_init_scrobar_rect(grRect, &frTemp, GOC_NO_STATE|GOC_NO_SELECT, 7 /*dense mesh*/, LINEDIR_NONE))
		if(!_init_scrobar_rect(grRect, &frTemp, STATE_SCROLL_BAR, 7 /*dense mesh*/, LINEDIR_NONE))
		/// end ALLOW_DELETE_SCROLLBAR
			return false;
		grRect.SetName(strRect);
	}
	
	gl.RemoveGraphObject(strThumb);
	GraphObject grThumb = gl.CreateGraphObject(GROT_RECT);	
    // move thumb into correct position    
    double f1 = (ax1 - x1)/(x2-x1);
    double f2 = (ax2 - x1)/(x2-x1);
    /// Hong 03/27/07 v8.0590 FIX_RESET_SCALE_THUMB_NOT_CORRECT_UPDATE
    //if(f1 < 0 || f1 > 1) f1 = 0;
    //if(f2 <0 || f2 > 1 || f2 < f1) f2 = 1;
    if(bResetScale || f1 < 0 || f1 > 1) f1 = 0;
    if(bResetScale || f2 <0 || f2 > 1 || f2 < f1) f2 = 1;
    /// end FIX_RESET_SCALE_THUMB_NOT_CORRECT_UPDATE
    
    double thumbX1 = Rectx1 + f1*(Rectx2-Rectx1);
    double thumbX2 = Rectx1 + f2*(Rectx2-Rectx1);
	if( bHorizontal )
	{
		fr.left = thumbX1;
		fr.right = thumbX2;
	}
	else
	{
		/// Hong 03/07/07 QA80-9286-P7 FIX_ERROR_POSITION_FOR_VERTICAL_THUMB_LINE_WHEN_MOVING
		//fr.top = thumbX1;
		//fr.bottom = thumbX2;
		///Kyle 04/28/2009 FIX_ENDLESS_REFRESH_IN_OLD_PROJECT
		//fr.top = thumbX2;
		//fr.bottom = thumbX1;
		fr.top = 1 - thumbX2;
		fr.bottom = 1 - thumbX1;
		///End FIX_ENDLESS_REFRESH_IN_OLD_PROJECT
		/// end FIX_ERROR_POSITION_FOR_VERTICAL_THUMB_LINE_WHEN_MOVING
	}
	/// Hong 03/23/07 V8.0588 ALLOW_DELETE_SCROLLBAR
	//if(!_init_scrobar_rect(grThumb, &fr, GOC_NO_ROTATE|GOC_NO_SKEW|GOC_NO_EDIT, 0 , bHorizontal ? LINEDIR_VERTICAL : LINEDIR_HORIZONTAL, script, GRCT_ANY_EVENT))//GRCT_ANY_EVENT, GRCT_SIZEMOVE))
	if(!_init_scrobar_rect(grThumb, &fr, STATE_SCROLL_THUMB, 0 , bHorizontal ? LINEDIR_VERTICAL : LINEDIR_HORIZONTAL, script, GRCT_ANY_EVENT))//GRCT_ANY_EVENT, GRCT_SIZEMOVE))
	/// end ALLOW_DELETE_SCROLLBAR
		return false;
	
	grThumb.SetName(strThumb);
	///Kyle 12/18/2008 QA80-12156-P8 v8.0988 SET_SCROLLBAR_AND_SCROLLTHUMB_ATTACH_TO_LAYER
	grRect.Attach = 0;
	grThumb.Attach = 0;
	///End SET_SCROLLBAR_AND_SCROLLTHUMB_ATTACH_TO_LAYER
	RECT rectConfine = {CONFINE_CONNECTOR_RECT_ZERO_MARGIN, 0, 0, 0};
    grRect.ConnectTo(grThumb, -1, -1, FALSE, OCR_SITE1, &rectConfine);
    // x1 x2 should be saved into layer storage, so that we can access it from LT later
    info_set_section(gl, trRange, SCROLLBAR_RANGE);
  
    /// Hong 03/23/07 v8.0588 MORE_OPTION_ALLOW_NOT_RESCALE_ON_INIT
    if ( bResetScale )
    {
    /// end MORE_OPTION_ALLOW_NOT_RESCALE_ON_INIT
	    /// Hong 03/07/07 QA80-9286-S4 RESCALE_LAYER_BY_RANGE_ON_INIT
	    if( bHorizontal )
		{
			gl.X.From = x1;
			gl.X.To = x2;
			/// Hong 03/27/07 v8.0590 QA80-9286-P9 FIX_Y_SCROLLBAR_FAIL_UPDATE_LINK
			LT_execute("x1=x1"); //force update X axis
			/// end FIX_Y_SCROLLBAR_FAIL_UPDATE_LINK
		}
		else
		{
			gl.Y.From = x1;
			gl.Y.To = x2;
			/// Hong 03/27/07 v8.0590 QA80-9286-P9 FIX_Y_SCROLLBAR_FAIL_UPDATE_LINK
			LT_execute("y1=y1"); //force update Y axis
			/// end FIX_Y_SCROLLBAR_FAIL_UPDATE_LINK
		}
		
	/// Hong 03/23/07 v8.0588 MORE_OPTION_ALLOW_NOT_RESCALE_ON_INIT
    }
	/// end MORE_OPTION_ALLOW_NOT_RESCALE_ON_INIT
    /// end RESCALE_LAYER_BY_RANGE_ON_INIT
    //---- CPY 2/23/2007 AXIS_SCROLLBAR_NEEDS_TO_WORK_FROM_LOADING_OPJ
    // this will need to be done when select thumb
    //_set_vertical_lines(gl, x1, x2, false, bHorizontal);
    //----
    
	s_asBar.Update(gl, strThumb, bHorizontal, false);		///Kyle 11/24/2008 QA80-12156-P1 UPDATE_RANGE_WHEN_GRAPH_SCALE_CHANGING
   	return true;
}





////////////////////////////////////////////////////////////////////////////////
//// begin LT Callable OC functions ////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

//---	CPY 12/6/06 QA70-12736 LT_NEED_MORE_CNTRL_ON_ALLOWING_OC_FUNCS
//#pragma labtalk(1)
#pragma labtalk(2)
//---
// return false on events that are not processed and should be handled by LT
int graph_scrollbar_events(int nEvent, string strName, bool bHorizontal = true)
{
	/// Hong 06/13/08 QA80-11694 ORIGIN_CRASH_WHEN_RESCALE_WITH_MULTIPLE_SCROLLBAR_EXIST
	/* when OE_SCALE_CHANGE fired by scrollbar context menu in multiple scrollbars case, Project.ActiveLayer() leads to crash
	if(nEvent == OE_UPDATE)  // drawing event
		return true;
	GraphObject gr;
	gr = gl.GraphObjects(strName);
	FRECT fr;	
	*/
#ifdef	AXIS_SCROLLBAR_DEBUG
	out_int("", nEvent);
#endif	//AXIS_SCROLLBAR_DEBUG
	/// end ORIGIN_CRASH_WHEN_RESCALE_WITH_MULTIPLE_SCROLLBAR_EXIST
	if(OE_SELECT == nEvent)
	{
		/// Hong 06/13/08 QA80-11694 ORIGIN_CRASH_WHEN_RESCALE_WITH_MULTIPLE_SCROLLBAR_EXIST
		GraphLayer gl = Project.ActiveLayer();
		/// end ORIGIN_CRASH_WHEN_RESCALE_WITH_MULTIPLE_SCROLLBAR_EXIST

		///Kyle 04/28/2009 FIX_ENDLESS_REFRESH_IN_OLD_PROJECT
		// maybe it's not a good solution
		/*
		if(gl)
		{
			string strRectToDel, strThumbToDel;
			if(bHorizontal)
			{
				strRectToDel = Y_SCROLL_BAR_NAME;
				strThumbToDel = Y_SCROLL_THUMB_NAME;
			}
			else
			{
				strRectToDel = X_SCROLL_BAR_NAME;
				strThumbToDel = X_SCROLL_THUMB_NAME;
			}
			gl.RemoveGraphObject(strRectToDel);
			gl.RemoveGraphObject(strThumbToDel);
		}
		*/
		///End FIX_ENDLESS_REFRESH_IN_OLD_PROJECT
		s_asBar.Update(gl, strName, bHorizontal);
		return true;
	}
	
	if(nEvent == OE_MOVING || nEvent == OE_RESIZING)
	{
		s_asBar.ShowThumbPositions();
		return true;
	}	
	
	if(nEvent == OE_MOVE || nEvent == OE_RESIZE)
	{		
		/// Hong 06/05/07 QA80-9286-P10 FIX_THUMB_SIZE_NOT_CORRECT_AFTER_MOVED
		//s_asBar.UpdateLayer();
		s_asBar.UpdateLayer( nEvent == OE_MOVE ? false : true );
		/// end FIX_THUMB_SIZE_NOT_CORRECT_AFTER_MOVED
		//----Iris 02/14/2007 v8.0562 
		//By Easwar's seggestion, "After the scroll/zoom is done, the blue line is useless and gets in the way....that is why we suggest removing it after the scroll/zoom has been done"
		s_asBar.ShowThumbLines(false);
		//----
		return true;
	}	
	
	if(nEvent == OE_UNSELECT)
	{
		s_asBar.SaveSettings();
		return true;
	}
	
	///Kyle 11/24/2008 QA80-12156-P1 UPDATE_RANGE_WHEN_GRAPH_SCALE_CHANGING
	if(nEvent == OE_SCALE_CHANGE)
	{
		GraphLayer gl = Project.ActiveLayer();
		if(!gl)
			return false;
		s_asBar.ExtendRange(gl, strName, bHorizontal);
		s_asBar.UpdateThumb(gl);
	}
	///End UPDATE_RANGE_WHEN_GRAPH_SCALE_CHANGING
	
	///Kyle 11/25/2008 QA80-12156-P2 UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT
	if(nEvent == OE_UPDATE)
	{
		GraphLayer gl = Project.ActiveLayer();
		if(!gl)
			return false;
		s_asBar.UpdateOnChange(gl, strName, bHorizontal);
	}
	///End UPDATE_AXIS_SCROLLBAR_ON_ORIGIN_EVENT
	
	return true;

}


////////////////////////////////////////////////////////////////////////////////
////   end LT Callable OC functions ////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
