/*------------------------------------------------------------------------------*
 * File Name: GraphObjTools.h 													*
 * Creation: Sim 01-08-2010														*
 * Purpose: OriginC Source C file												*
 * Copyright (c) Originlab Corp. 2006											*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	Sophy 1/18/2010 CLEAN_CODE_SUPPORT_FLEXIBLE_COLOR_SETTING_ACCESS			*
 *	Sophy 1/19/2010 QA80-14832 ADD_SAVE_THEME_AS_IN_CONTEXT_MENU_FOR_ROI_TOOLS	*
 *	Sophy 1/19/2010 QA80-14832 SHOW_TOOLNAME_FOR_ROI_TOOLS						*
 *	Folger 01/21/09 QA81-14995 GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
 *	Sophy 1/21/2010 QA80-14832 DISPLAY_DEFAULT_THEME_NAME_WHEN_SAVE_THEME_FOR_ROI_TOOL
 *	Sophy 1/22/2010 QA80-14996 GR_OBJ_NEED_MOVE_EVENT_WHEN_UNDO_MOVE_OPERATION_FOR_QUICK_FIT
 *	CPY 1/22/10 QA81-15020 CLOSE_BUTTON_USE_SIMPLER_LT_BASED_CODE				*
 *	Sophy 01/23/10 QA80-15015 GROBJ_NEED_OPTION_CTRL_DELETE_OPERATION_UNDOABLE_OR_NOT
 *	Sophy 1/26/2010 ADD_GO_TO_REPORT_TABLE_MENU_IN_CONTEXT						*
 *	Sophy 1/27/2010 FILTER_UNSUITABLE_PLOTTYPE_IN_CONTEXT_MENU					*
 *  Iris 1/27/2010 ADD_LEFTX_RIGHTX_IN_ROI_TAB									*
 *	Sophy 1/29/2010 ROI_ATTACHED_LINES_FAIL_TO_SET_POSITION_CORRECTLY_FOR_THE_FIRST_TIME
 *	Folger 02/01/10 CURRENT_THEME_NAME_SHOULD_SHOW_WHEN_SAVE_THEME_AS_IN_ROI_TOOLS
 *	Sophy 2/1/2010 SHOW_DATA_TIME_STAMP_WHEN_OUTPUT_TO_SCRIPT_WINDOW			*
 *	Hong 02/01/10 QA80-14832 FIX_ROI_BOX_FAIL_DISPLAY_CORRECT_POSITION_IN_DATA_DISPLAY_DLG_WHEN_CREATE
 *	Sophy 2/2/2010 RESET_TOP_LABEL_POS_WHEN_CHANGE_FUNC_OR_PREFERENCES			*
 *	CPY 2/2/10 QA81-15066 CONTEXT_MENU_POPUP_POSITION_MAKE_CONSISTENT			*
 *	Sophy 2/3/2010 ROI_CONTEXT_MENU_DATAPLOT_SHOW_LEGEND_AS_IN_NLFIT			*
 *	Sophy 2/4/2010 PROPERLY_UPDATE_GROBJ_POSITION_ACCORDING_TO_LAYER_SCALE		*
 *	Folger 02/04/10 SUPPORT_LOAD_THEME_IN_ROI_TOOLS_CONTEXT_MENU				*
 *	Sophy 2/4/2010 QA80-15080 VERSION_CHECKING_FOR_ROI_COMPATIBILITY			*
 *	Folger 02/04/10 SUPPORT_AUTO_FOR_X_SCALE									*
 *	Sophy 2/5/2010 FAIL_TO_LOAD_THEME_WITH_DUPLICATED_IDS						*
 *	Sophy 2/8/2010 ROI_STATS_CURVE_NEED_TO_DELAY_HANDLE_SCALE_CHANGE			*
 *	Iris 2/10/2010 QA81-15099 FIX_BAD_ROI_INIT_POS_WHEN_LAYER_FROM_LARGE_THAN_TO*
 *	Sophy 2/10/2010 QA81-15097 ROI_TOOLS_DONT_WORK_WHEN_XY_AXIS_EXCHANGED		*
 *	Sophy 2/11/2010 QA81-15104-P3 REFRESH_GRAPH_ON_ROI_EXPAND					*
 *	Sophy 2/11/2010 FAIL_TO_LOAD_THEME_WITH_DUPLICATED_IDS						*
 *	Sophy 2/11/2010 QA81-15107 SUPPORT_EXTEND_POSITION_FOR_GRAPHOBJECT_CONNECT	*
 *	Iris 2/20/2010 MOVE_REPLACE_LAST_OUTPUT_TO_CONTEXT_MENU						*
 *  Iris 2/20/2010 QUICKFIT_SHOULD_USE_SELECTED_PLOT_NOT_ACTIVE_PLOT_AS_INPUT	*
 *	Sophy 2/22/2010 QA81-14930 IMPROVE_CODE_FOR_ROI_TOOLS						*
 *	Folger 02/23/10 ROI_TOOLS_DO_EXPAND_FAILS_TO_PLACE_BUTTONS_CORRECTLY		*
 *  Iris 2/25/2010 TO_FIX_ALWAYS_CHANGE_LAYER_SCALE_WHEN_EXPAND_FULL_RANGE		*
 *  Iris 2/25/2010 FIX_EXPAND_FULL_RANGE_FIT_CURVE_UPWARD_MOVED					*
 *	Sophy 3/1/2010 OC_WORKAROUND_FOR_CONNECTED_OBJ_WRONG_POSITION_ON_LAYER_RESIZE
 *	Kenny 03/05/2010 QA81-14832 QUICK_FIT_WRONG_AUTO_PREVIEW_FITTED_CURVE_COLOR	*
 *	Kyle 03/08/2010 CUSTOM_CMD_IN_CONTEXT_MENU_OF_GRAPH_OBJ_TOOLS				*
 *	Kyle 03/12/2010 PICK_PEAK_SHARE_CODE_WITH_QUICK_FIT							*
 *	Kyle 03/15/2010 IS_PLOT_FOR_ROI_GIVE_OPTION_TO_SPECIFY_THE_NAME_TO_TAG_A_DATAOBJ
 *	Sophy 3/19/2010 QA81-15217 CLONE_MAIN_OBJ_ON_OUTPUT_FOR_ROI_TOOLS			*
 *	Sophy 3/30/2010 QA81-15217-S1 MORE_WORK_ON_CLONE_MAIN_OBJ					*
 *	Folger 04/08/10 ROI_TEXT_LABEL_SHOULD_BE_WHITEOUT							*
 *	Sophy 4/9/2010 QA81-15290 QUICK_STATS_SHOW_PREVIEW_LINE_LABELS				*
 *	Foler 04/12/10 QA81-15288 QUICKFIT_BACKWARD_COMPATIBILITY_FOR_81SR2			*
 *	Sophy 4/13/2010 SUPPORT_CHANGE_DERIV_ORDER_FROM_CONTEXT_MENU				*
 *	Sophy 4/14/2010 BACKWORD_COMPATIBILITY_SUPPORT_FOR_GADGET_ATTACHMENTS		*
 *	Folger 04/16/10 QA81-15311 GR_BUTTON_OBJ_RECT_SHADOW_REMAINED_AFTER_DESTROY	*
 *	Sophy 4/29/2010 QUICKFIT_EXPAND_TO_FULL_RANGE_SHOULD_UPDATE_X_SCALE			*
 *	Sophy 4/29/2010 ORG-59 DATAPOINTS_OPERATION_SHOULD_ALLOW_UNDO				*
 *	Sophy 4/29/2010 ORG-59 REGION_STATS_GADGET_SHOULD_SEL_ALL_PLOTS_BY_DEFAULT	*
 *	Sophy 5/5/2010 EXPAND_FULL_RANGE_SHOULD_DO_NOTHING_WHEN_ALL_POINTS_ARE_MISSING_VALUE
 *	Sophy 6/8/2010 ORG-48-P9 FAIL_TO_DEFAUL_THEME_FROM_CONTEXT_MENU				*
 *	Sophy 6/8/2010 ORG-48-P10 PROPER_GET_DATAPLOT_POINTS_FOR_EXPAND_FULL_RANGE	*
 *	Sophy 6/13/2010 ORG-23-S5 SHOW_APPLY_BUTTON_FOR_INTERP_PREFERENCE_DLG		*
 *	Kyle 09/08/2010 ORG-998-P6 SHOW_BASELINE_INSIDE_THE_RECTANGLE_ONLY			*
 *	Folger 09/14/2010 PICK_PEAK_GADGET_FAILED_TO_WORK_AFTER_RELOAD_PROJECT		*
 *	Sophy 10/15/2010 ORG-1263-P1 UPDATE_INDICATOR_SETTINGS_FOR_RISETIME_TOOL	*
 *	Sophy 10/15/2010 ORG-1265-P1 PROPER_INIT_ROI_POSITION_WITH_LARGE_MAGNITUDE_X_VALUES
 *------------------------------------------------------------------------------*/
 
#include <Origin.h>
#include <Control.h>
#include <GetNBox.h>
#include <..\OriginLab\OriginEvents.h>
#include <..\Originlab\theme_utils.h>
#include "grobj_utils.h"
#include "GraphObjTools.h"
#include "GraphObjToolDlg.h"
#include <xfutils.h>

#pragma labtalk(0)



int	roi_tool_option_access(DWORD dwTestBit, int nOption)
{
	static	DWORD _ROICtrl = 0;
	#ifdef	_DEBUG
	DWORD dwTemp = _ROICtrl;
	#endif	/// _DEBUG
	if ( ROI_OP_GET == nOption )
		return (_ROICtrl & dwTestBit);
	else if ( ROI_OP_SET == nOption )
	{
		_ROICtrl |= dwTestBit;
		return _ROICtrl;
	}
	else if ( ROI_OP_REMOVE == nOption )
	{
		_ROICtrl &= ~dwTestBit;
		return _ROICtrl;
	}
	else if ( ROI_OP_RESET )
	{
		_ROICtrl = 0;
		return _ROICtrl;
	}
	return 0;
}

///Sophy 2/10/2010 QA81-15097 ROI_TOOLS_DONT_WORK_WHEN_XY_AXIS_EXCHANGED
bool	is_active_graphlayer_xyexchanged()
{
	int nExchangeXY = 0;
	_LT_Obj
	{
		nExchangeXY = layer.exchangexy;
	}
	return (0 != nExchangeXY);
}
///end ROI_TOOLS_DONT_WORK_WHEN_XY_AXIS_EXCHANGED

///Sophy 3/8/2010 EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
///Kyle 03/15/2010 IS_PLOT_FOR_ROI_GIVE_OPTION_TO_SPECIFY_THE_NAME_TO_TAG_A_DATAOBJ
//bool	is_plot_for_ROI(const DataPlot& dp, const GraphObject& gr, vector<int>& vnI1, vector<int>& vnI2) // NULL, NULL
bool	is_plot_for_ROI(const DataPlot& dp, const GraphObject& gr, LPCSTR lpcszTag, vector<int>& vnI1, vector<int>& vnI2) // NULL, NULL, NULL
///End IS_PLOT_FOR_ROI_GIVE_OPTION_TO_SPECIFY_THE_NAME_TO_TAG_A_DATAOBJ
{
	if ( !dp || !gr )
		return false;
	vector<int> vI1, vI2;
	XYRange xySrc;
	Column colY;
	
	if ( (dp.GetDataRegions(gr, vI1, vI2) > 0) )
	{
		///Kyle 03/15/2010 IS_PLOT_FOR_ROI_GIVE_OPTION_TO_SPECIFY_THE_NAME_TO_TAG_A_DATAOBJ
		//if ( dp.GetDataRange(xySrc) && xySrc.GetYColumn(colY) && is_dataobj_tagged(colY, STR_DATASETOBJ_FITCURVE) )
		//	return false;
		if( lpcszTag )
		{
			if ( dp.GetDataRange(xySrc) && xySrc.GetYColumn(colY) && is_dataobj_tagged(colY, lpcszTag) )
				return false;
		}
		///End IS_PLOT_FOR_ROI_GIVE_OPTION_TO_SPECIFY_THE_NAME_TO_TAG_A_DATAOBJ
		if ( !_is_plot_suitable_for_ROI(dp.GetPlotType()) )
			return false;
		
		if ( vnI1 )
			vnI1 = vI1;
		if ( vnI2 )
			vnI2 = vI2;
		
		return true;
	}
	return false;
}

bool	update_roi_position(GraphObject& go, double dLeft, double dTop, double dRight, double dBottom)
{
	if ( !go )
		return false;
	
	vector vx(4), vy(4);
	vx[0] = dLeft, vx[1] = dRight; vx[2] = dRight; vx[3] = dLeft;
	vy[0] = dTop, vy[1] = dTop; vy[2] = dBottom; vy[3] = dBottom;
	Tree tr;
	tr = go.GetFormat(FPB_DATA, FOB_ALL, true, true);
	tr.Root.Data.X.dVals = vx;
	tr.Root.Data.Y.dVals = vy;

	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}

///Kyle 03/12/2010 PICK_PEAK_SHARE_CODE_WITH_QUICK_FIT, moved from QuickFit.c
int get_source_data_plot_index_from_ROI(const GraphObject& go)
{
	Tree trInfo;
	int nPlotIndex = -1;
	if ( go && tree_get_binary_storage(trInfo, go, ATTACHED_GRAPH_OBJECTS_INFO) && trInfo.curPlotIndex )
		nPlotIndex = trInfo.curPlotIndex.nVal;
	else
		nPlotIndex = get_selected_data_plot();
	return nPlotIndex;
}

static bool _get_rect_ROI_init_x_range(const GraphLayer& gl, double& x0, double& x1)
{
	if( !gl )
		return false;
	double dx = fabs(gl.X.To - gl.X.From);
	double min = dx * 0.2;
	double max = dx * 0.7;
	double from = gl.X.From;
	double to = gl.X.To;
	x0 = (from < to? from : to) + (from < to ? min : max);
	x1 = (from < to? from : to) + (from < to ? max : min);

	return true;
}

bool check_get_roi_x_position(const GraphLayer& gl, string& strLeft, string& strRight, LPCSTR lpcszRect)
{
	double x0, x1;

	GraphObject go;
	FRECT rr;
	if( lpcszRect && *lpcszRect && (go = gl.GraphObjects(lpcszRect)) && get_go_rect(go, rr) )
	{
		x0 = rr.left;
		x1 = rr.right;
	}
	else
	{
		if( !_get_rect_ROI_init_x_range(gl, x0, x1) )
			return false;
	}
	
	int nPlot = get_source_data_plot_index_from_ROI(go);
	DataPlot dp;
	if( nPlot>=0 && (dp=gl.DataPlots(nPlot)) )
	{
		strLeft = get_value_by_format(dp, x0);
		strRight = get_value_by_format(dp, x1);
	}
	else
	{
		///Sophy 10/15/2010 ORG-1265-P1 PROPER_INIT_ROI_POSITION_WITH_LARGE_MAGNITUDE_X_VALUES
		//strLeft = ftoa(x0, "*"); 	when x0 = 2451080.1 and x1 = 2451082.85
		//strRight = ftoa(x1, "*"); these two strLeft & strRight got same values, the area becomes a line, and is not good.
		strLeft = ftoa(x0);
		strRight = ftoa(x1);
		///end PROPER_INIT_ROI_POSITION_WITH_LARGE_MAGNITUDE_X_VALUES
	}

	return true;
}

///End PICK_PEAK_SHARE_CODE_WITH_QUICK_FIT

bool	get_ROI_main_obj_name(const GraphLayer& gl, LPCSTR lpcszROIType, string& strObjName)
{
	if ( !gl )
		return false;
	
	Tree tr;
	if ( !gl.GetBinaryStorage(STR_ROI_MAIN_OBJ_STORAGE, tr) )
		return false;
	
	TreeNode trROIType = tr.GetNode(lpcszROIType);
	if ( !trROIType )
		return false;
	
	strObjName = trROIType.strVal;
	GraphObject go = gl.GraphObjects(strObjName);
	return go.IsValid();
}

bool	set_ROI_main_obj_name(const GraphLayer& gl, LPCSTR lpcszROIType, LPCSTR lpcszObjName)
{
	if ( !gl )
		return false;
	
	Tree tr;
	gl.GetBinaryStorage(STR_ROI_MAIN_OBJ_STORAGE, tr);
	TreeNode trROIType = tree_check_get_node(tr, lpcszROIType);
	if ( NULL == lpcszObjName )
	{
#ifdef	_DEBUG
		string strMsg;
		strMsg.Format("Clear Obj Name for %s : %s", lpcszROIType, trROIType.strVal);
		out_str(strMsg);
#endif	//_DEBUG
		trROIType.strVal = ""; //clear
	}
	else
	{
		GraphObject go = gl.GraphObjects(lpcszObjName);
		if ( !go )
			return false;
		
		trROIType.strVal = lpcszObjName;
#ifdef	_DEBUG
		string strMsg;
		strMsg.Format("Set Obj Name for %s : %s", lpcszROIType, trROIType.strVal);
		out_str(strMsg);
#endif	//_DEBUG
	}
	gl.PutBinaryStorage(STR_ROI_MAIN_OBJ_STORAGE, tr);
	return true;
}
///end EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL

///Sophy 6/13/2010 ORG-23-S5 SHOW_APPLY_BUTTON_FOR_INTERP_PREFERENCE_DLG
bool	ROI_apply_handle(TreeNode& tr)
{
	string strLTCmd;
	string strXFName;
	string strMainObjName;
	if ( tr.GetAttribute(STR_XFNAME_ATTRIB, strXFName) && tr.GetAttribute(STR_MAINOBJ_NAME_ATTRIB, strMainObjName) )
	{
		GraphObjCurveTool gBaseTool(strMainObjName);
		gBaseTool.SetGUITree(tr);
		strLTCmd.Format("run.section(graph_controls.ogs, GraphToolEvent, %s %s %d %d);", strXFName, strMainObjName, OE_BUTTONCLICK, GOT_BTN_APPLY);	
		LT_execute(strLTCmd);
	}
	return true;
}
///end SHOW_APPLY_BUTTON_FOR_INTERP_PREFERENCE_DLG

///--------------------- Sophy 9/13/2008 GRAPH_OBJ_TOOL_BASE_CLASS
#define	GRAPH_TOOL_SETTINGS		"GraphToolSettings"
#define GRAPH_TOOL_CLASS_INFO	"GraphToolClassInfo"
GraphObjTool::GraphObjTool(LPCSTR lpcszMainObjName)
{
	///---Sim 01-08-2010 QA81-14930 CLEAN_GRAPH_OBJ_TOOLS
	/*
	GraphPage gp = Project.Pages();
	if(!gp)
		return;

	GraphLayer gl = gp.Layers();//Layers(0);CPY 9/24/08 QA70-92268 GR_SHOULD_ALLOW_ON_MULTI_LAYER_GRAPH
	if(!gl)
	{
		return;
	}
	m_gp = gp;
	m_gl = gl;
	m_attObjNames.SetSize( CTP_SIZE );
	connectToObj(lpcszMainObjName);
	*/
	m_strGrName = "";
	
	m_vnObjIDs.SetSize(0);
	m_vsObjNames.SetSize(0);
	
	m_vnObjIDs.Add(GOT_OBJ_CLOSE);
	m_vsObjNames.Add("Close");

	m_nRightTopObjs = 0;	
	
	if ( lpcszMainObjName )
		Init(lpcszMainObjName);
	///---END QA81-14930 CLEAN_GRAPH_OBJ_TOOLS
	m_gapCtrl.xGap = 0.2;
	m_gapCtrl.yGap = 0.2;

}

//---- CPY 9/26/08 QA70-12266 ADDTOOL_XF_NEEDS_PROJ_VAR_TO_INDICATE_THEY_ARE_STILL_ACTIVE
int GraphObjTool::GetTotalNumTools()
{
	string strVar = GetSignature();
	double dd = 0;
	LT_get_var(strVar, &dd);
	return dd;
}
BOOL GraphObjTool::OnDestroy()
{
	referenceCount(false);
	///Sophy 3/8/2010 EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
	set_ROI_main_obj_name(m_gl, GetXFName());	 //clear information
	///end EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL

	///------ Folger 04/16/10 QA81-15311 GR_BUTTON_OBJ_RECT_SHADOW_REMAINED_AFTER_DESTROY
	#ifndef		__ENLARGE_GR_OBJ_ERASE_INFLATE_SIZE__
	if ( m_gp )
		m_gp.Refresh();
	#endif		/// __ENLARGE_GR_OBJ_ERASE_INFLATE_SIZE__
	///------ End GR_BUTTON_OBJ_RECT_SHADOW_REMAINED_AFTER_DESTROY
	return true;
}

/// Fisher 2008-9-18 For OnDestroy()
/*
In some tool like basic curve FFT, The preview graph and the temp data worksheet 
were shared by multiple tools. So their destructor cannot simply delete the preview
graph and temp data wks, we need a mechanism to specify a count of the 
number of references to it held by other objects, If an object's shared count 
reaches zero, the object has become deletable.

CPY removed Fisher's code and condence it to referenceCount
*/

// use Project variable to keep track of the number of instances of a gr tool
int GraphObjTool::referenceCount(bool bInc) // true to increment, false to decrement
{
	string strVar = GetSignature();
	double dd = 0;
	LT_get_var(strVar, &dd);
	dd = dd + (bInc? 1:-1);
	if(dd <= 0)
	{
		string strLT;
		strLT.Format("del -v %s", strVar);
		LT_execute(strLT);
	}
	else
		LT_set_var(strVar, dd);
	return (int)dd;
}
//----

//----- CPY 9/17/08 CLEANUP_CODE_RELATED_TO_USING_BASE_CLASS_SET_TREE
//	virtual 
///---Sim 01-08-2010 QA81-14930 CLEAN_GRAPH_OBJ_TOOLS
//BOOL GraphObjTool::Init()
BOOL GraphObjTool::Init(LPCSTR lpcszMainObjName)
///---END QA81-14930 CLEAN_GRAPH_OBJ_TOOLS
{
	///---Sim 01-08-2010 QA81-14930 CLEAN_GRAPH_OBJ_TOOLS
	//if(!IsValidLayer())
		//return false;
	//
	//if(!IsValidGrObj())
	//{
		//ASSERT(false);
		//return false;
	//}
	//set_go_behind_data(m_go);
	////set_go_user_deleteable(m_go, true);CPY 9/23/08 this is now done as part of set_LT_script
//
	///// YuI 09/24/08 QA70-12264 OPTION_TO_SELECT_GR_OBJECT_BEFORE_DATA
	//set_go_hittest_before_data(m_go);
	///// end OPTION_TO_SELECT_GR_OBJECT_BEFORE_DATA
//
	//referenceCount(true);//---- CPY 9/26/08 QA70-12266 ADDTOOL_XF_NEEDS_PROJ_VAR_TO_INDICATE_THEY_ARE_STILL_ACTIVE
	
	if ( !connectToObj(lpcszMainObjName) )
		return false;
	///---END QA81-14930 CLEAN_GRAPH_OBJ_TOOLS
	return true;
}

BOOL	GraphObjTool::GetMainObjName(string& strObjName)
{
	if ( m_go )
	{
		strObjName = m_go.GetName();
		return TRUE;
	}
	return FALSE;
}

//---- CPY 9/27/08 CENTRALIZE_ADD_RECT_FOR_ALL_TOOLS
bool GraphObjTool::Attach(LPCSTR lpcszMainObjName)
{
	///---Sim 01-08-2010 QA81-14930 CLEAN_GRAPH_OBJ_TOOLS
	///Sophy 2/22/2010 QA81-14930 IMPROVE_CODE_FOR_ROI_TOOLS
	//if ( !m_gp )
	//{
		//GraphPage gp = Project.Pages();
		//if(!gp)
			//return false;
		//m_gp = gp;
	//}
	//if ( !m_gl )
	//{
		//GraphLayer gl = m_gp.Layers();//Layers(0);CPY 9/24/08 QA70-92268 GR_SHOULD_ALLOW_ON_MULTI_LAYER_GRAPH
		//if(!gl)
		//{
			//return false;
		//}
		//m_gl = gl;
	//}
	m_gp = Project.Pages();
	if ( !m_gp )
		return false;
	
	m_gl = m_gp.Layers();
	if ( !m_gl )
		return false;
	///end IMPROVE_CODE_FOR_ROI_TOOLS
	///---END QA81-14930 CLEAN_GRAPH_OBJ_TOOLS
	
	if(lpcszMainObjName && *lpcszMainObjName != '\0' )
	{
		//ASSERT(m_strGrName.IsEmpty());
		m_strGrName = lpcszMainObjName;
		m_go = m_gl.GraphObjects(m_strGrName);
		if(m_go)
			return true;
	}
	return false;
}
//virtual 
void GraphObjTool::OnMoving()
{
	if(!IsValidGrObj())
		return;
	
	///--- Sandy 2008-12-10 centralize and update the string to data display as well, 
	//						since the status bar shows the x info But kept on blinking so user can really use it
	/*
	FRECT frect;
	m_go.GetTempBoundingBox(&frect);
	string str;
	double x1 = m_gl.X.From;
	double x2 = m_gl.X.To;
	double xx1 = x1 + frect.left * (x2-x1);
	double xx2 = x1 + frect.right * (x2-x1);
	
	str.Format("x= %g - %g, dx= %g", xx1, xx2, xx2-xx1);
	*/
	string str;
	//_get_go_bounding_box_info(m_go, str);
	getBoundingBoxInfo(str);
	
	if(!str.IsEmpty())
		SetDataDisplayText(str);
	
	
	SetStatusBarText(str);
}

///Sophy 2/8/2010 ROI_STATS_CURVE_NEED_TO_DELAY_HANDLE_SCALE_CHANGE
#define	ROI_DELAY_EXECUTE_EX(_DirtyBit, _EventID, _Code, _Msg)	{	\
	if ( !QUERY_ROI_TOOL_OPTION(_DirtyBit) )	\
	{	\
		roi_tool_option_access(_DirtyBit, ROI_OP_SET);	\
		string strLT;	\
		strLT.Format(";run.section(graph_controls.ogs, GraphToolEvent, %s %s %d %d);", GetXFName(), m_go ? m_go.GetName() : "Rect", _EventID, _Msg);	\
		LT_execute(strLT);	\
	}	\
	else	\
	{	\
		_Code;	\
		roi_tool_option_access(_DirtyBit, ROI_OP_REMOVE);	\
	} \
}

#define	ROI_DELAY_EXECUTE(_DirtyBit, _EventID, _Code)		ROI_DELAY_EXECUTE_EX(_DirtyBit, _EventID, _Code, 0)
///end ROI_STATS_CURVE_NEED_TO_DELAY_HANDLE_SCALE_CHANGE

///Sophy 7/19/2010 ORG-25-P8 MULTAI_GADGETS_ON_SAME_LAYER_FAIL_TO_UPDATE_CORRECTLY_ON_RESCALE
#define	ROI_DELAY_RESCALE(_Msg)	{	\
	if ( GROBJEVENTS_SELF_DELAY_EVENT == _Msg )	\
	{	\
		m_gp.Refresh(TRUE);	\
		OnRescale();	\
	}	\
	else	\
	{	\
		string strLT;	\
		strLT.Format(";run.section(graph_controls.ogs, GraphToolEvent, %s %s %d %d);", GetXFName(), m_go ? m_go.GetName() : "Rect", OE_SCALE_CHANGE, GROBJEVENTS_SELF_DELAY_EVENT);	\
		LT_execute(strLT);	\
	}	\
}
///end MULTAI_GADGETS_ON_SAME_LAYER_FAIL_TO_UPDATE_CORRECTLY_ON_RESCALE
	
void GraphObjTool::OnEvent(int nEvent, int nMsg)
{
	switch(nEvent)
	{
	///Sophy 2/4/2010 QA80-15080 VERSION_CHECKING_FOR_ROI_COMPATIBILITY
	///------ Foler 04/12/10 QA81-15288 QUICKFIT_BACKWARD_COMPATIBILITY_FOR_81SR2
	case OE_WIN_OPEN:  /// when oen OGG, there is no OE_WIN_ACTIVATE, so this is a tricky solution since OE_WIN_ACTIVATE will be posted in ROI_DELAY_EXECUTE
		///Sophy 6/10/2010 ORG-48-P14 BETTER_EVENT_HANDLE_FOR_PREFERENCE_IN_ROI_TOOLS
		//need to update event handler whenever load opj or ogg
		int* pnXFEvtHandlerState = GetXFEventHandlersState();
		if ( pnXFEvtHandlerState != NULL )
			*pnXFEvtHandlerState = 0;
		///end BETTER_EVENT_HANDLE_FOR_PREFERENCE_IN_ROI_TOOLS
	///------ End QUICKFIT_BACKWARD_COMPATIBILITY_FOR_81SR2
	case OE_WIN_ACTIVATE: //when opj load, the page may not be active and fail to check version, so need to check when activated.
		///Sophy 2/8/2010 ROI_STATS_CURVE_NEED_TO_DELAY_HANDLE_SCALE_CHANGE
		//CheckROIVersion();
		//if ( !roi_tool_option_access(ROI_OPTION_VERSION_CHECKED, ROI_OP_GET) ) //not checked, maybe GUI tree not ready, should delay check.
		//{
			//string strLT;
			//strLT.Format(";run.section(graph_controls.ogs, GraphToolEvent, %s %s %d);", GetXFName(), m_go.GetName(), OE_WIN_OPEN);
			//LT_execute(strLT);
		//}
		//else
			//roi_tool_option_access(ROI_OPTION_VERSION_CHECKED, ROI_OP_REMOVE); //if checked, should be removed for other ROI to use.
		ROI_DELAY_EXECUTE(ROI_OPTION_VERSION_CHECKED, OE_WIN_ACTIVATE, CheckROIVersion());
		///end ROI_STATS_CURVE_NEED_TO_DELAY_HANDLE_SCALE_CHANGE
		
		break;
	///end VERSION_CHECKING_FOR_ROI_COMPATIBILITY
	case OE_MOVING:
	case OE_RESIZING:
		OnMoving();
		break;
	case OE_MOVE:
	case OE_RESIZE:
		{
			ROIToolOptionAccessHelper*		pclHelper = NULL;
			if ( O_QUERY_BOOL(nMsg, GROBJEVENTS_FROM_EVENT_FUNCTION) )
				pclHelper = new ROIToolOptionAccessHelper(ROI_OPTION_ON_MOVE_EVENT);
			OnMove();
			NICE_SAFE_REMOVAL(pclHelper);
		}
		break;
	/// Fisher 7/20/09 QA80-13975 HANDLE_RESCALE_EVENT_FOR_GRAPH_OBJ_TOOL
	case OE_SCALE_CHANGE:
		///Sophy 2/8/2010 ROI_STATS_CURVE_NEED_TO_DELAY_HANDLE_SCALE_CHANGE
		if ( IsDelayUpdate() )
		{
			///Sophy 7/19/2010 ORG-25-P8 MULTAI_GADGETS_ON_SAME_LAYER_FAIL_TO_UPDATE_CORRECTLY_ON_RESCALE
			//ROI_DELAY_EXECUTE(ROI_OPTION_SCALE_CHANGED, OE_SCALE_CHANGE, OnRescale());
			ROI_DELAY_RESCALE(nMsg);
			///end MULTAI_GADGETS_ON_SAME_LAYER_FAIL_TO_UPDATE_CORRECTLY_ON_RESCALE
		}
		else
		{
			OnRescale();
		}
		///end ROI_STATS_CURVE_NEED_TO_DELAY_HANDLE_SCALE_CHANGE
		break;
	/// End HANDLE_RESCALE_EVENT_FOR_GRAPH_OBJ_TOOL
	///Sophy 12/4/2009 QA80-14799 EXPOSE_DATAMASK_EVENT_TO_OC_GRAPHOBJECT
	case OE_DATAMASK_CHANGE:
		OnMasked();
		break;
	///end EXPOSE_DATAMASK_EVENT_TO_OC_GRAPHOBJECT
	case OE_WIN_CLOSE:
	case OE_DELETE:
		//printf("%d: on Destroy\n", nEvent);
		OnDestroy();
		break;
		
	case OE_BUTTONCLICK:
//---- CPY 1/22/10 QA81-15020 CLOSE_BUTTON_USE_SIMPLER_LT_BASED_CODE
//		switch(nMsg)
//		{
		break;
//----
///---Sim 01-08-2010 QA81-14930 CLEAN_GRAPH_OBJ_TOOLS
/*
#ifndef	_ROI_TOOL_NEW_MENU_
		case GOT_BTN_PLOTS:
			DoShowPlots();
			break;
		case GOT_BTN_OUTPUT:
			DoOutput();
			break;
		case GOT_BTN_EDIT:
			DoEdit();
			break;
			
		case GOT_BTN_FUNCTION:
			DoFunction();
			break;
#else
		case GOT_BTN_CONTEXT:
			DoContext();
			break;
#endif	//_ROI_TOOL_NEW_MENU_		
*/
///---END QA81-14930 CLEAN_GRAPH_OBJ_TOOLS
//---- CPY 1/22/10 QA81-15020 CLOSE_BUTTON_USE_SIMPLER_LT_BASED_CODE
//		case GOT_BTN_CLOSE:
//			DestroyInternal();
//			break;
//		}
//----
	default:
		//out_int("other even = ", nEvent);
	}
}
//----

bool GraphObjTool::connectToObj(LPCSTR lpcszMainObjName)
{
	if( Attach(lpcszMainObjName) )
		///---Sim 01-08-2010 QA81-14930 CLEAN_GRAPH_OBJ_TOOLS
		//return readClassInfo();
		return loadClassInfo();
		///---END QA81-14930 CLEAN_GRAPH_OBJ_TOOLS
	
	return false;
}

/*
void GraphObjTool::saveClassInfo()
{
	if(!m_go)
	{
		ASSERT(false);
		return;
	}
	Tree tr;
	tr.attObjNames.strVals = m_attObjNames;
	tree_put_binary_storage( tr, m_go, GRAPH_TOOL_CLASS_INFO );	
}

bool GraphObjTool::readClassInfo()
{
	if(m_go)
	{
		Tree tr;
		tree_get_binary_storage( tr, m_go, GRAPH_TOOL_CLASS_INFO );
		if(tr.attObjNames)
		{
			vector<string> vsTemp;
			vsTemp = tr.attObjNames.strVals;
			for(int ii = 0; ii < vsTemp.GetSize() && ii < CTP_SIZE; ii ++)
				m_attObjNames[ii] = vsTemp[ii];
			
			return true;
		}
	}
	return false;
}
*/
///---Sim 01-08-2010 QA81-14930 CLEAN_GRAPH_OBJ_TOOLS
bool	GraphObjTool::saveClassInfo()
{
	if(!IsValidLayer())
		return false;
	
	if(!IsValidGrObj())
	{
		ASSERT(false);
		return false;
	}
	
	Tree tr;
	if ( !SaveClassInfo(tr) )
		return false;
	if ( !tree_put_binary_storage( tr, m_go, GRAPH_TOOL_CLASS_INFO ) )
		return false;
	
	return true;
}
bool	GraphObjTool::loadClassInfo()
{
	if(!IsValidLayer())
		return false;
	
	if(!IsValidGrObj())
	{
		ASSERT(false);
		return false;
	}
	
	Tree tr;
	if ( tree_get_binary_storage( tr, m_go, GRAPH_TOOL_CLASS_INFO ) )
	{
		if ( !LoadClassInfo(tr) )
			return false;
	}
	
	return true;
}
///---END QA81-14930 CLEAN_GRAPH_OBJ_TOOLS
void GraphObjTool::AddNewLine(string& str, string strNew)
{
	if(!str.IsEmpty())
		str += "\r\n";
	
	str += strNew;
}


//-----
//------ CPY 1/22/10 QA81-15020 CLOSE_BUTTON_USE_SIMPLER_LT_BASED_CODE
/*
///Sophy 1/5/2010 QA80-14904-S1 CLEAN_CODE_FOR_ROI_TOOLS
void GraphObjTool::DestroyInternal()
{
	if ( m_go )
	{
		string strScript;
		strScript.Format("run.section(graph_controls, DestroyObjects, %s %d %s);", m_gp.GetName(), m_gl.GetIndex() + 1, m_go.GetName());
		LT_execute(strScript);
		OnDestroy();
	}
}
*/
//------ end CLOSE_BUTTON_USE_SIMPLER_LT_BASED_CODE
 
/*
int	GraphObjTool::CreateAdvancedButtons(LPCSTR lpcszXFName, DWORD dwCtrl)
{
	int nNumBtns = 0;
	string strScript;
	if ( dwCtrl & GOT_BTN_CLOSE )
	{
		check_create_attachment(m_go, m_goClose, "\z(0)", GROT_TEXT, CTP_INNER_RIGHT_TOP, CJ_VIEW_X_GAP_N | CJ_VIEW_Y_GAP_N);
		strScript.Format("run.section(graph_controls, GraphToolEvent, %s %s %d %d);", lpcszXFName, m_go.GetName(), OE_BUTTONCLICK, GOT_BTN_CLOSE);
		set_LT_script(m_goClose, strScript, GRCT_MOUSEUP, 1);
		nNumBtns++;
	}
#ifndef	_ROI_TOOL_NEW_MENU_	
	if ( dwCtrl & GOT_BTN_PLOTS )
	{
		check_create_attachment(m_go, m_goPlots, "\z(12)", GROT_TEXT, CTP_RIGHT_TOP, CJ_VIEW_X_GAP_N | CJ_VIEW_Y_GAP_L);
		strScript.Format("run.section(graph_controls, GraphToolEvent, %s %s %d %d);", lpcszXFName, m_go.GetName(), OE_BUTTONCLICK, GOT_BTN_PLOTS);
		set_LT_script(m_goPlots, strScript, GRCT_MOUSEUP, 1);
		nNumBtns++;
	}
	if ( dwCtrl & GOT_BTN_OUTPUT )
	{
		check_create_attachment(m_go, m_goOutput, " + ", GROT_TEXT, CTP_RIGHT_TOP, CJ_VIEW_X_GAP_N | CJ_VIEW_Y_GAP_XL);
		strScript.Format("run.section(graph_controls, GraphToolEvent, %s %s %d %d);", lpcszXFName, m_go.GetName(), OE_BUTTONCLICK, GOT_BTN_OUTPUT);
		set_LT_script(m_goOutput, strScript, GRCT_MOUSEUP, 1);
		nNumBtns++;
	}
	if ( dwCtrl & GOT_BTN_EDIT )
	{
		check_create_attachment(m_go, m_goEdit, "... ", GROT_TEXT, CTP_RIGHT_TOP, CJ_VIEW_X_GAP_N | CJ_VIEW_Y_GAP_XXL);
		strScript.Format("run.section(graph_controls, GraphToolEvent, %s %s %d %d);", lpcszXFName, m_go.GetName(), OE_BUTTONCLICK, GOT_BTN_EDIT);
		set_LT_script(m_goEdit, strScript, GRCT_MOUSEUP, 1);
		nNumBtns++;
	}
#else
	if ( dwCtrl & GOT_BTN_CONTEXT )
	{
		check_create_attachment(m_go, m_goContext, "\z(12)", GROT_TEXT, CTP_RIGHT_TOP, CJ_VIEW_X_GAP_N | CJ_VIEW_Y_GAP_N);
		strScript.Format("run.section(graph_controls, GraphToolEvent, %s %s %d %d);", lpcszXFName, m_go.GetName(), OE_BUTTONCLICK, GOT_BTN_CONTEXT);
		set_LT_script(m_goContext, strScript, GRCT_MOUSEUP, 1);
		nNumBtns++;
	}
#endif	//_ROI_TOOL_NEW_MENU_
	return nNumBtns;
}
*/
///END QA80-14904-S1 CLEAN_CODE_FOR_ROI_TOOLS

BOOL	GraphObjTool::OnPreMove()
{
	if(!IsValidLayer())
		return false;
	
	if( !IsValidGrObj() )
		return false;
	return true;// derived class can return false to prevent OnMove handling
}

BOOL	GraphObjTool::SetTree( const TreeNode& tr )
{
	return tree_put_binary_storage( tr, m_go, GRAPH_TOOL_SETTINGS );
}
BOOL	GraphObjTool::GetTree( TreeNode& tr )
{
	///Sophy 1/19/2010 QA80-14832 ADD_SAVE_THEME_AS_IN_CONTEXT_MENU_FOR_ROI_TOOLS
	//return tree_get_binary_storage( tr, m_go, GRAPH_TOOL_SETTINGS );
	if ( !tr || !m_go )
		return FALSE;
	BOOL bRet = tree_get_binary_storage( tr, m_go, GRAPH_TOOL_SETTINGS );
	tr.SetAttribute(STR_CLASS_OPTION_NAME_ATTRIB, GetXFName());
	return bRet;
	///end ADD_SAVE_THEME_AS_IN_CONTEXT_MENU_FOR_ROI_TOOLS
}
//----- CPY 9/17/08 CLEANUP_CODE_RELATED_TO_USING_BASE_CLASS_SET_TREE
/*
int	GraphObjTool::GetAttachmentCount()
{
	vector<uint>	vUIDs;
	m_go.GetConnectedObjects( vUIDs );
	return vUIDs.GetSize();
}
*/
//-----

//--- CPY 9/23/08 BASELINE_NEED_TO_BE_CONNECTED
// returns <0 for err, 1 if already existed and type correct then just get out, 0 if normal creation on empty slot
//int	GraphObjTool::CreateAttachedFreeLine(GraphObject* pgo, int nPos)
//int	GraphObjTool::CreateAttachedFreeLine(GraphObject* pgo, int nPos, int nLineType)
int		GraphObjTool::CreateAttachedFreeLine(GraphObject* pgo, int nPos ,  int nLineType, int nColor)///-------Sandy 2008-12-9 add color option
{
	/// Hong 12/12/08 v8.0986 CLEAN_MAGIC_NUMBER
	//if( !IsValidLayer() || !IsValidGrObj() || nPos > 2 || nPos < 0)
	if( !IsValidLayer() || !IsValidGrObj() || nPos >= CTP_FREE_NUM || nPos < 0)
	/// end CLEAN_MAGIC_NUMBER
		return -1;
	
	///----- Sandy 2008-12-2 add ployline as one kind of free line, and only support these two type of line
	if(nLineType != GROBJ_TN_POLYLINE && nLineType != GROBJ_TN_LINE2 )
		return -1;
	
	GraphObject go;
	
	///----- Sandy 2008-12-2 add ployline as one kind of free line
	//if(GetAttachment(CTP_FREE_1 + nPos, go, GROBJ_TN_LINE2) > 0)
	int nType;
	//if(GetAttachment(CTP_FREE_1 + nPos, go, nLineType) > 0)
	// to do
	if ( 0 == GetAttachment(go, 0) )
	{
		// TO_DO to add code to compare type, if wrong type, will need to destroy it and continue
		go.GetObjectType(&nType); ///Sandy 2008-12-4 I don't know why runtime error happen here
		if(nType == nLineType)
		{
			// return 1 only if type is correct
			if(pgo)
			{
				*pgo = go;
			}
			
			return 1;
		}
	}
	//-----
	
	///----- Sandy 2008-12-2 add ployline as one kind of free line
	//if(!add_line(m_gl, go))
		//return -2;
	
	//add code to compare type, if wrong type, will need to destroy it and continue
	if(go)
		go.Destroy();
	
	switch(nLineType)
	{
	case GROBJ_TN_LINE2:
		if(!add_line(m_gl, go))
			return -2;
		break;
	case GROBJ_TN_POLYLINE:
		go = m_gl.CreateGraphObject(GROBJ_TN_POLYLINE);
		if(!go)
			return -2;
		break;
	default:
			return -2;
		break;
	}
	//------end 
		
	if(pgo)
		*pgo = go;
	
	///Sandy 2008-12-9 add 
	if(!set_go_color(go, nColor))
		error_report("Fail to free line color in GraphObjTool::CreateAttachedFreeLine()");	
		
	set_go_selectable(go, false);
	// to do
	//m_attObjNames[CTP_FREE_1 + nPos] = go.GetName();
	///Sophy 1/4/2010 QA80-14916 LT_COMMAND_GET_ALL_CONNECTED_GRAPHOBJECTS
	//m_go.ConnectTo(go, -1, -1, false, 0);
	go.ConnectTo(m_go, -1, -1, false, 0); //make m_go as unique ROOT in the connected graphobject tree.
	///end LT_COMMAND_GET_ALL_CONNECTED_GRAPHOBJECTS
	saveClassInfo();
	
	return 0;
}
//--- end BASELINE_NEED_TO_BE_CONNECTED



/// YuI 09/23/08 by CP's request cleaning unnecesary code
//	#define MASTER "master"
/// end YuI 09/23/08 

// returns <0 for err, 1 if already existed and type correct then just get out, 0 if normal creation on empty slot
/*
int	GraphObjTool::CreateAttachment(int nObjType, int nPos, GraphObject* pgo, LPCSTR lpcszInitText, int nParam)
{
	if( !IsValidLayer() || !IsValidGrObj() || nPos >= CTP_SIZE || nObjType > GROBJ_TN_SCALER )
		return -1;
	//----- CPY 9/17/08 CLEANUP_CODE_RELATED_TO_USING_BASE_CLASS_SET_TREE
	//ASSERT( m_attObjNames[nPos].IsEmpty() ); //allow create objects on same position?
	GraphObject go;
	if(GetAttachment(nPos, go, nObjType) > 0)
	{
		// TO_DO to add code to compare type, if wrong type, will need to destroy it and continue
		// return 1 only if type is correct
		if(pgo)
			*pgo = go;
		return 1;
	}
	//-----
	go = m_gl.CreateGraphObject( nObjType );

	/// YuI 09/23/08 by CP's request cleaning unnecesary code
	/#
	/// Fisher 2008-9-19
	Tree tr;
	tr.master.strVal = m_go.GetName();
	go.PutBinaryStorage(MASTER, tr);
	/// End Fisher
	#/
	/// end YuI 09/23/08 
	
	if( nPos > CTP_AUTO ) //nPos > -1
		m_attObjNames[nPos] = go.GetName();
	bool bRet = connect_justify( m_go, go, nPos );
	if(pgo)
		*pgo = go;
	
	//----- CPY 9/17/08 CLEANUP_CODE_RELATED_TO_USING_BASE_CLASS_SET_TREE
	if(GROBJ_TN_TEXT == nObjType)
	{
		go.Text = lpcszInitText? lpcszInitText: " "; // must have something
		Tree tr;
		///---- Folger 09/24/08, Max suggestted default 18 font size is better, CPY added nParam
	 	//tr.Root.Font.Size.nVal = 14;
	 	///------ Folger 05/06/09 MAX_SUGGEST_BIGGER_FONT_SIZE_FOR_GRAPH_OBJ_TEXT
	 	//tr.Root.Font.Size.nVal = nParam > 0? nParam: 18;
	 	tr.Root.Font.Size.nVal = nParam > 0? nParam: 24;
	 	///------ End MAX_SUGGEST_BIGGER_FONT_SIZE_FOR_GRAPH_OBJ_TEXT
	 	///----
	 	tr.Root.States.nVal = GOC_NO_RESIZE | GOC_NO_ROTATE | GOC_NO_SKEW | GOC_NO_EDIT | GOC_NO_BORDERSIZE | GOC_NO_IN_PLACE_EDIT;//CPY 9/24/08 moved to here from curve_integ XF
	 	//----- CPY 9/24/08 CENTER_LABEL_ON_TOOL_AFTER_ROMAN_ADD_SUCH_SUPPORT
	 	if(nPos == CTP_TOP || CTP_BOTTOM == nPos)
	 		tr.Root.Alignment.Horizontal.nVal = 1;// center
	 	//-----
		go.UpdateThemeIDs(tr.Root);
		go.ApplyFormat(tr, true, true);
	}		
	// and need to save into binary storage
	saveClassInfo();
	//-----

	return bRet?0:-1;//need to continue...
}



// return 0 if not such obj in given position
// return -1 if nObjType >=
// return 1 if found obj
int		GraphObjTool::GetAttachment(int nPos, GraphObject& go, int nObjType)
{
	if( nPos < 0 || nPos >= CTP_SIZE || nObjType > GROBJ_TN_SCALER ) //Sophy, should not allow CTP_AUTO ?
		return -1;
	if( m_attObjNames[nPos].IsEmpty() )
		return 0;
	
	vector<uint>	vUIDs;
	if ( m_go.GetConnectedObjects( vUIDs ) > 0 )
	{
		GraphObject gotmp;
		for( int ii = 0; ii < vUIDs.GetSize(); ii++ )
		{	
			gotmp = Project.GetObject( vUIDs[ii] );
			if( gotmp.GetName().CompareNoCase(m_attObjNames[nPos]) == 0 )
			{
				go = gotmp;
				return 1;
			}
		}
	}
	return 0;
}
*/

///Sophy 1/11/2010 CLEAN_GRAPHOBJTOOL_CODE
int	GraphObjTool::CreateAttachment(GraphObject& go, int nObjID, int nPos, int nObjType, LPCSTR lpcszInitText, int nParam)
{
	go = m_gl.CreateGraphObject(nObjType);
	///Sophy 1/29/2010 ROI_ATTACHED_LINES_FAIL_TO_SET_POSITION_CORRECTLY_FOR_THE_FIRST_TIME
	if ( GROT_LINE == nObjType || GROT_POLYLINE == nObjType || GROT_POLYGON == nObjType ) ///Sophy 2/24/2010 quick fit preview curve
		go.Attach = ATTACH_TO_SCALE;
	///end ROI_ATTACHED_LINES_FAIL_TO_SET_POSITION_CORRECTLY_FOR_THE_FIRST_TIME
	
	if ( GROBJ_TN_TEXT == nObjType )
	{
		go.Text = lpcszInitText ? lpcszInitText : " ";
		Tree trFormat;
		trFormat.Root.Font.Size.nVal = nParam > 0 ? nParam : 16;
		trFormat.Root.States.nVal = GOC_NO_RESIZE | GOC_NO_ROTATE | GOC_NO_SKEW | GOC_NO_EDIT | GOC_NO_BORDERSIZE | GOC_NO_IN_PLACE_EDIT;
		if ( CTP_TOP == nPos || CTP_BOTTOM == nPos )
			trFormat.Root.Alignment.Horizontal.nVal = 1;
		///------ Folger 04/08/10 ROI_TEXT_LABEL_SHOULD_BE_WHITEOUT
		trFormat.Root.TextWhiteOut.nVal = 1;
		///------ End ROI_TEXT_LABEL_SHOULD_BE_WHITEOUT

		go.UpdateThemeIDs(trFormat.Root);
		go.ApplyFormat(trFormat, true, true);
	}
	go.SetName(getAttObjName(nObjID));
	
	bool bRet = connect_justify(m_go, go, nPos, &m_gapCtrl);
	if ( nPos == CTP_RIGHT_TOP )
		m_nRightTopObjs++;
	
	///Sophy 01/23/10 QA80-15015 GROBJ_NEED_OPTION_CTRL_DELETE_OPERATION_UNDOABLE_OR_NOT
	string strLT;
	strLT.Format("%s.DelUndoable=0;", go.GetName());
	LT_execute(strLT);
	///end GROBJ_NEED_OPTION_CTRL_DELETE_OPERATION_UNDOABLE_OR_NOT
	
	return (bRet ? 0 : -1);
}

int		GraphObjTool::GetAttachment(GraphObject& go, int nObjID)
{
	string strObjName = getAttObjName(nObjID);
	go = m_gl.GraphObjects(strObjName);
	if ( go )
		return 0;
	return -1;
}


///Sophy 1/14/2010 MOVE_CLOSE_BUTTON_TO_BASE_CLASS
//virtual
int		GraphObjTool::CreateAttachments()
{
	for ( int ii = 0; ii < m_vnObjIDs.GetSize(); ii++ )
	{
		GraphObject go;
		string strScript;
		switch ( m_vnObjIDs[ii] )
		{
		case GOT_OBJ_CLOSE:
			CreateAttachment(go, m_vnObjIDs[ii], CTP_INNER_RIGHT_TOP, GROT_TEXT, "\z(0)");
			//---- CPY 1/22/10 QA81-15020 CLOSE_BUTTON_USE_SIMPLER_LT_BASED_CODE
			//strScript.Format("run.section(graph_controls, GraphToolEvent, %s %s %d %d);", GetXFName(), m_go.GetName(), OE_BUTTONCLICK, GOT_BTN_CLOSE);
			strScript="run.section(graph_controls, OnROICloseButton)";
			//----
			set_LT_script(go, strScript, GRCT_MOUSEUP, 1);
			break;
		}
	}
	return 0;
}
//virtual
int		GraphObjTool::GetAttachments()
{
	int nRet = GetAttachment(m_goClose, GOT_OBJ_CLOSE);
	if ( 0 != nRet )
		return nRet;
	return 0
}
///end MOVE_CLOSE_BUTTON_TO_BASE_CLASS

string	GraphObjTool::getAttObjName(int nObjID)
{
	string strObjName = "";
	int nObjIndex = find_in_list(nObjID, m_vnObjIDs, false);
	if ( nObjIndex >= 0 )
	{
		ASSERT(m_go);
		if ( m_go )
			strObjName += m_go.GetName();
		strObjName += m_vsObjNames[nObjIndex];
	}
	return strObjName;
}
///end CLEAN_GRAPHOBJTOOL_CODE


///Sandy 2008-12-23 move in GraphObjCurveTool class as member function
void GraphObjTool:: getBoundingBoxInfo(string& str)
{
	if(m_go)
	{
		if(m_gl)
		{
			FRECT frect;
			m_go.GetTempBoundingBox(&frect);
			/// Hong 02/01/10 QA80-14832 FIX_ROI_BOX_FAIL_DISPLAY_CORRECT_POSITION_IN_DATA_DISPLAY_DLG_WHEN_CREATE
			/*
			double x1 = m_gl.X.From;
			double x2 = m_gl.X.To;
			double xx1 = x1 + frect.left * (x2-x1);
			double xx2 = x1 + frect.right * (x2-x1);
			*/
			double		xx1 = frect.left, xx2 = frect.right;
			ASSERT( ATTACH_TO_PAGE != m_go.Attach );
			if ( ATTACH_TO_LAYER == m_go.Attach ) // return value of GetTempBoundingBox is in percentage
			{
				double 	x1 = m_gl.X.From;
				double 	x2 = m_gl.X.To;
				xx1 = x1 + frect.left * (x2-x1);
				xx2 = x1 + frect.right * (x2-x1);
			}
			/// end FIX_ROI_BOX_FAIL_DISPLAY_CORRECT_POSITION_IN_DATA_DISPLAY_DLG_WHEN_CREATE
			///Sophy 12/31/2009 QA80-14904-S2 BETTER_NOTATION_IN_DISPLAY_WINDOW_FOR_ROI_TOOLS
			//str.Format("x= %g - %g, dx= %g", xx1, xx2, xx2-xx1);
			str.Format("x= %g to %g, dx= %g", xx1, xx2, xx2-xx1);
			///end BETTER_NOTATION_IN_DISPLAY_WINDOW_FOR_ROI_TOOLS
		}
	}
}

///--------------------- end Sophy 9/13/2008 GRAPH_OBJ_TOOL_BASE_CLASS

//////////////////////////////////////////////////////////////////////////////////////////////////
/// Fisher 2008-9-13	GRAPH_OBJ_CURVE_TOOL
//////////////////////////////////////////////////////////////////////////////////////////////////
GraphObjCurveTool::GraphObjCurveTool(LPCSTR lpcszMainObjName) : GraphObjTool(lpcszMainObjName)
{
	//---- CPY 10/1/08 MOVE_DATA_DISPLAY_CODE_TO_BASE_CLASS
	m_i1 = m_i2 = -1;
	m_x1 = m_x2 = NANUM;
	//----
	m_vnObjIDs.Add(GOT_OBJ_LABEL);
	m_vsObjNames.Add("Label");
	
	m_vnObjIDs.Add(GOT_OBJ_CONTEXT);
	m_vsObjNames.Add("Context");
}

///---Sim 01-08-2010 QA81-14930 CLEAN_GRAPH_OBJ_TOOLS
//virtual
BOOL GraphObjCurveTool::Init(LPCSTR lpcszMainObjName)
{
	if ( !GraphObjTool::Init(lpcszMainObjName) )
		return false;
	
	if ( 0 != GetAttachments() )
		return false;
	
	return true;
}
///---END QA81-14930 CLEAN_GRAPH_OBJ_TOOLS

///Sophy 2/4/2010 QA80-15080 VERSION_CHECKING_FOR_ROI_COMPATIBILITY
//virtual
bool	GraphObjCurveTool::CheckROIVersion()
{
	double dCurVersion = GetVersion();
	double dOldVersion;
	Tree trGUI;
	if ( GetGUITree(trGUI) )
	{
		///Sophy 3/4/2010 QA80-15080 VERSION_CHECKING_FOR_ROI_COMPATIBILITY
		string	strToolXFName; //if storage XFName not consistent with current XFName, should NOT check version
		if ( trGUI.GetAttribute(STR_XFNAME_ATTRIB, strToolXFName) && strToolXFName.CompareNoCase(GetXFName()) != 0 )
			return false;
		//end VERSION_CHECKING_FOR_ROI_COMPATIBILITY
		if ( !trGUI.GetAttribute(STR_VERSION_ATTRIB, dOldVersion) ) //if no attribute set, default as 8.0
			dOldVersion = 8.0;
		///------ Foler 04/12/10 QA81-15288 QUICKFIT_BACKWARD_COMPATIBILITY_FOR_81SR2
		//if ( dOldVersion < dCurVersion )
		if ( (int)(dOldVersion * 10) != (int)(dCurVersion * 10) )
		///------ End QUICKFIT_BACKWARD_COMPATIBILITY_FOR_81SR2
		{
			///Sophy 2/8/2010 ROI_STATS_CURVE_NEED_TO_DELAY_HANDLE_SCALE_CHANGE centralize code
			//roi_tool_option_access(ROI_OPTION_RESET_LABEL_POS, ROI_OP_SET);
			///end ROI_STATS_CURVE_NEED_TO_DELAY_HANDLE_SCALE_CHANGE
			string	strMsg = _L("The panel tool %s is incompatible with current Origin version.\nPlease remove it and add a new one from the Gadgets menu.");
			strMsg.Format(strMsg, GetPreferenceTitle());
			if ( !UpdateTopLabel(strMsg) ) //maybe the text not exist, should dump to script window.
			{
				LT_execute("type -a");
				out_str(strMsg);
			}
		}
		///------ Foler 04/12/10 QA81-15288 QUICKFIT_BACKWARD_COMPATIBILITY_FOR_81SR2
		else if ( dOldVersion < dCurVersion )
		{
			RemakeGUITree();
			CheckCreateAttachments();	///Sophy 4/14/2010 BACKWORD_COMPATIBILITY_SUPPORT_FOR_GADGET_ATTACHMENTS
		}
		///------ End QUICKFIT_BACKWARD_COMPATIBILITY_FOR_81SR2
		return true;
	}
	return false;
}
bool	GraphObjCurveTool::SetVersion()
{
	double dCurVersion = GetVersion();
	Tree trGUI;
	if ( GetGUITree(trGUI) )
	{
		trGUI.SetAttribute(STR_XFNAME_ATTRIB, GetXFName());	///Sophy 3/4/2010 QA80-15080 VERSION_CHECKING_FOR_ROI_COMPATIBILITY
		trGUI.SetAttribute(STR_VERSION_ATTRIB, dCurVersion);
		trGUI.SetAttribute(STR_MAINOBJ_NAME_ATTRIB, m_go.GetName());	///Sophy 6/13/2010 ORG-23-S5 SHOW_APPLY_BUTTON_FOR_INTERP_PREFERENCE_DLG
		SetGUITree(trGUI);
		return true;
	}
	return false;
}
///end VERSION_CHECKING_FOR_ROI_COMPATIBILITY

//------ CPY 10/1/08 MOVE_DATA_DISPLAY_CODE_TO_BASE_CLASS
/*
BOOL GraphObjCurveTool::GetData(DataPlot& dp, int& i1, int& i2)
{
	ASSERT(IsValidGrObj());
	if(!m_go) return false; // release level checking		
	return find_intersect_dataplot(m_go, dp, i1, i2);
*/
///Sophy 5/4/2010 QA82-15364-P2 ROI_TOOLS_OPTION_FOR_SKIP_ALL_MASKED_DATAPOINTS
//BOOL GraphObjCurveTool::GetData()
BOOL GraphObjCurveTool::GetData(DWORD dwCtrl /*=GROBJ_DATA_DEFAULT*/)
///end ROI_TOOLS_OPTION_FOR_SKIP_ALL_MASKED_DATAPOINTS
{
	ASSERT(IsValidGrObj());
	if(!m_go)
		return false; // release level checking		
	ROIToolOptionAccessHelper	clHelper(ROI_OPTION_IGNORE_EVENT);
	///Sophy 5/4/2010 QA82-15364-P2 ROI_TOOLS_OPTION_FOR_SKIP_ALL_MASKED_DATAPOINTS
	//if(!find_intersect_dataplot(m_go, m_dp, m_i1, m_i2))
	int nNoMissing = 0;
	if( !find_intersect_dataplot(m_go, m_dp, m_i1, m_i2) || ((dwCtrl & GROBJ_SKIP_ALL_MASKED_DATA) && (nNoMissing = m_dp.GetDataPoints(m_i1, m_i2, m_vX, m_vY)) <= 0) )
	///end ROI_TOOLS_OPTION_FOR_SKIP_ALL_MASKED_DATAPOINTS
	{
		///Sophy 1/23/2010 MAKE_QUICK_CURVE_STATS_AS_STANDARD_ROI_TOOL
		string strHints = _L("No Data Selected");
		UpdateTopLabel(strHints);
		///end MAKE_QUICK_CURVE_STATS_AS_STANDARD_ROI_TOOL
		m_i1 = m_i2 = -1;
		return false;
	}
	///Sophy 1/25/2010 SHOW_WARNING_ON_NOT_GETTTING_ENOUGH_DATA_POINTS
	///Sophy 5/4/2010 QA82-15364-P2 ROI_TOOLS_OPTION_FOR_SKIP_ALL_MASKED_DATAPOINTS
	//else if ( (m_i2 - m_i1 + 1) < GetPointsLimit() )
	else if ( nNoMissing < GetPointsLimit() )
	///end ROI_TOOLS_OPTION_FOR_SKIP_ALL_MASKED_DATAPOINTS
	{
		string strHints = _L("%s requires at least %d points");
		strHints.Format(strHints, GetToolName(), GetPointsLimit());
		UpdateTopLabel(strHints);
		m_i1 = m_i2 = -1;
		return false;
	}
	///end SHOW_WARNING_ON_NOT_GETTTING_ENOUGH_DATA_POINTS
	m_dp.GetDataPoint(m_i1, &m_x1, NULL);
	m_dp.GetDataPoint(m_i2, &m_x2, NULL);
	SetPlot(m_dp.GetIndex()); /// Iris 2/20/2010 QUICKFIT_SHOULD_USE_SELECTED_PLOT_NOT_ACTIVE_PLOT_AS_INPUT
	return true;
}

/// YuI 10/09/08 QA70-12265-P3 CURVE_STATS_QUICK_TOOL_MUST_BE_SMARTER
///Sophy 12/14/2009 QA80-14686-P2 DATAPLOT_GET_DATAPOINTS_NEED_TO_SKIP_MASKED_DATA
//BOOL GraphObjCurveTool::GetData(vector& vX, vector& vY)
BOOL GraphObjCurveTool::GetData(vector& vX, vector& vY, DWORD dwCtrl)
///end DATAPLOT_GET_DATAPOINTS_NEED_TO_SKIP_MASKED_DATA
{
	///Sophy 12/14/2009 QA80-14686-P2 DATAPLOT_GET_DATAPOINTS_NEED_TO_SKIP_MASKED_DATA
	//return find_intersect_dataplot(m_go, m_dp, vX, vY);
	///Sophy 1/23/2010 MAKE_QUICK_CURVE_STATS_AS_STANDARD_ROI_TOOL
	//return find_intersect_dataplot(m_go, m_dp, vX, vY, true, dwCtrl);
	ROIToolOptionAccessHelper	clHelper(ROI_OPTION_IGNORE_EVENT);
	///Sophy 5/4/2010 QA82-15364-P2 ROI_TOOLS_OPTION_FOR_SKIP_ALL_MASKED_DATAPOINTS
	//if ( !find_intersect_dataplot(m_go, m_dp, vX, vY, true, dwCtrl) )
	if ( !find_intersect_dataplot(m_go, m_dp, vX, vY, true, dwCtrl) || ((dwCtrl & GROBJ_SKIP_ALL_MASKED_DATA) && m_dp.GetDataPoints(m_go, m_vX, m_vY, NULL, dwCtrl) <= 0) )
	///end ROI_TOOLS_OPTION_FOR_SKIP_ALL_MASKED_DATAPOINTS
	{
		string strHints = _L("No Data Selected");
		UpdateTopLabel(strHints);
		return false;
	}
	///Sophy 1/25/2010 SHOW_WARNING_ON_NOT_GETTTING_ENOUGH_DATA_POINTS
	else if ( vX.GetSize() < GetPointsLimit() )
	{
		string strHints = _L("%s requires at least %d points");
		strHints.Format(strHints, GetToolName(), GetPointsLimit());
		UpdateTopLabel(strHints);
		return false;
	}
	SetPlot(m_dp.GetIndex()); /// Iris 2/20/2010 QUICKFIT_SHOULD_USE_SELECTED_PLOT_NOT_ACTIVE_PLOT_AS_INPUT
	return true;
	///end MAKE_QUICK_CURVE_STATS_AS_STANDARD_ROI_TOOL
	///end DATAPLOT_GET_DATAPOINTS_NEED_TO_SKIP_MASKED_DATA
}
/// end CURVE_STATS_QUICK_TOOL_MUST_BE_SMARTER

///Sophy 3/19/2010 QA81-15217 CLONE_MAIN_OBJ_ON_OUTPUT_FOR_ROI_TOOLS
bool	GraphObjCurveTool::SetCloneMainObjName(LPCSTR lpcszName, LPCSTR lpcszTextName)
{
	Tree trInfo;
	tree_get_binary_storage(trInfo, m_go, ATTACHED_GRAPH_OBJECTS_INFO);
	trInfo.cloneROI.strVal = lpcszName;
	trInfo.cloneTextObj.strVal = lpcszTextName;
	tree_put_binary_storage(trInfo, m_go, ATTACHED_GRAPH_OBJECTS_INFO);
	
	return true;
}
bool	GraphObjCurveTool::GetCloneMainObjName(string& strName, string& strTextName)
{
	Tree trInfo;
	tree_get_binary_storage(trInfo, m_go, ATTACHED_GRAPH_OBJECTS_INFO);
	if ( trInfo.cloneROI )
	{
		strName = trInfo.cloneROI.strVal;
		strTextName = trInfo.cloneTextObj.strVal;
		return true;
	}
	return false;
}

static	void	_copy_format(const GraphObject& goSrc, GraphObject& goDst)
{
	if ( goSrc && goDst )
	{
#define	OBJ_FORMAT	(FPB_DIMENSION | FPB_STYLE | FPB_STYLE_FILL | FPB_OTHER | FPB_DATA)
		Tree trFmt;
		trFmt = goSrc.GetFormat(OBJ_FORMAT, FOB_ALL, true, true);
		goDst.ApplyFormat(trFmt, true, true);		
	}
}

///Sophy 4/9/2010 QA81-15290 QUICK_STATS_SHOW_PREVIEW_LINE_LABELS
//virtual
bool	GraphObjCurveTool::CloneAttachments(GraphObject& goCloneMain)
{
	if ( !goCloneMain )
		return false;
	//clone label object
	GraphObject gt;
	cloneObj(m_goLabel, gt);
	connectObj(goCloneMain, gt);
	
	SetCloneMainObjName(goCloneMain.GetName(), gt.GetName());
	
	return true;
}

bool	GraphObjCurveTool::CloneAndConnect(GraphObject& goCloneMain, GraphObject& goSrc)
{
	GraphObject gc;
	if ( cloneObj(goSrc, gc) )
		return connectObj(goCloneMain, gc);
	return false;
}

///Sophy 4/13/2010 SUPPORT_CHANGE_DERIV_ORDER_FROM_CONTEXT_MENU
bool	GraphObjCurveTool::InsertPopup(Menu& pm, uint nPosition, LPCSTR lpcszLabel, const vector<string>& vsItems, const vector<int>& vnCmdIDs, int nCheckIndex/* = -1*/)
{
	if ( vsItems.GetSize() != vnCmdIDs.GetSize() || vsItems.GetSize() == 0 )
		return false;
	
	Menu subMenu;
	for ( int iItem = 0; iItem < vsItems.GetSize(); iItem++ )
	{
		DWORD dwFlag = MF_STRING;
		if ( iItem == nCheckIndex )
			dwFlag |= MF_CHECKED;
		subMenu.Add(vsItems[iItem], vnCmdIDs[iItem], dwFlag);
	}
	pm.InsertPopup(nPosition, lpcszLabel, subMenu);
	return true;
}

bool	GraphObjCurveTool::InsertMenuItem(Menu& pm, uint nPosition, LPCSTR lpcszLabel, int nCmdID, UINT nFlags)
{
	pm.InsertMenu(nPosition, nFlags | MF_BYPOSITION, nCmdID, lpcszLabel);
	return true;
}

///end SUPPORT_CHANGE_DERIV_ORDER_FROM_CONTEXT_MENU


bool	GraphObjCurveTool::checkCloneMainObj()
{
	if ( IsCloneMainObj() && IsValidGrObj() )
	{
		//clone main object, without the script
		GraphObject gc;
		cloneObj(m_go, gc);
		
		//switch the index to keep orignial main object at the top for select and move again.
		int nIndexgo = m_go.GetIndex();
		int nIndexgc = gc.GetIndex();
		m_go.SetIndex(nIndexgc);
		gc.SetIndex(nIndexgo);
		///Sophy 3/30/2010 QA81-15217-S1 MORE_WORK_ON_CLONE_MAIN_OBJ
		disable_go_move(gc);
		CloneAttachments(gc);
		///end MORE_WORK_ON_CLONE_MAIN_OBJ
		MakePrintable(gc);	///Sophy 3/24/2010 QA80-15217-P1 MAKE_CLONED_MAIN_OBJECT_VISIBLE_PRINTIABLE
		m_gp.Refresh(); //refresh for better view of attachments of the main object.
		return true;
	}
	return false;
}

bool	GraphObjCurveTool::cloneObj(GraphObject& goSrc, GraphObject& goDst)
{
	if ( goSrc )
	{
		int nObjType;
		goSrc.GetObjectType(&nObjType);
		goDst = m_gl.CreateGraphObject(nObjType);
		if ( GROT_TEXT == nObjType )
			goDst.Text = goSrc.Text;
		_copy_format(goSrc, goDst);
		goDst.Attach = ATTACH_TO_SCALE;
		return true;
	}
	return false;
}

 //connect without justify, for cloned object
bool	GraphObjCurveTool::connectObj(GraphObject& goMain, GraphObject& go)
{
	if ( !goMain || !go )
		return false;
	RECT rectConfine = {-300, -300, 300, 300};
	return go.ConnectTo(goMain, CTP_AUTO, CTP_AUTO, FALSE, OCR_SITE2 | OCR_CNTRL_NOT_DRAW_EDGE_IF_UNSELECTABLE, &rectConfine);
}
///end QUICK_STATS_SHOW_PREVIEW_LINE_LABELS

bool	GraphObjCurveTool::updateLastCloneObjs()
{
	string strClonedObjName, strClonedTextName;
	if ( GetCloneMainObjName(strClonedObjName, strClonedTextName) )
	{
		GraphObject gc = m_gl.GraphObjects(strClonedObjName);
		GraphObject gt = m_gl.GraphObjects(strClonedTextName);
		if ( gc )
		{
			_copy_format(m_go, gc);
			///Sophy 3/30/2010 QA81-15217-S1 MORE_WORK_ON_CLONE_MAIN_OBJ
			disable_go_move(gc);
			if ( gt )
				gt.Text = m_goLabel.Text;
			///end MORE_WORK_ON_CLONE_MAIN_OBJ
			MakePrintable(gc);	///Sophy 3/24/2010 QA80-15217-P1 MAKE_CLONED_MAIN_OBJECT_VISIBLE_PRINTIABLE
			return true;
		}
	}
	return false;
}
///end CLONE_MAIN_OBJ_ON_OUTPUT_FOR_ROI_TOOLS

///Sandy 2008-12-23 move in GraphObjCurveTool class as member function
void GraphObjCurveTool:: getBoundingBoxInfo(string& str)
{
	string str1, str2;
	if(m_dp && m_i1 >=0 && m_i2 >=0)
	{
		string strLegend;
		m_dp.GetLegend(strLegend, NULL, false);
		str1.Format("%s[%d:%d]", strLegend, m_i1+1, m_i2+1);
	}
	
	GraphObjTool::getBoundingBoxInfo(str2);
	
	str = str1 + "\n" +str2;
}
//virtual
BOOL GraphObjCurveTool::OnMove()
{
	
	string strMsg;
	//if(m_dp && m_i1 >=0 && m_i2 >=0)
	//{
		//string strLegend;
		//m_dp.GetLegend(strLegend, NULL, false);
		//strMsg.Format("%s[%d:%d]", strLegend, m_i1+1, m_i2+1);
	//}
	
	//_get_go_bounding_box_info(m_go, strMsg);
	getBoundingBoxInfo(strMsg);
	
	if(!strMsg.IsEmpty())
		SetDataDisplayText(strMsg);
	
	///Sophy 2/1/2010 SHOW_DATA_TIME_STAMP_WHEN_OUTPUT_TO_SCRIPT_WINDOW
	SYSTEMTIME st;
	get_current_time(st);
	double dDate;
	if ( SystemTimeToJulianDate(&dDate, &st) )
	{
		Tree tr;
		GetTree(tr);
		tr.OpDateTime.strVal = GetToolName() + "(" + get_date_str(dDate) + ")";
		SetTree(tr);
	}
	///end SHOW_DATA_TIME_STAMP_WHEN_OUTPUT_TO_SCRIPT_WINDOW
	/////----Sandy 2008-12-10 update status bar when moving is stop as well
	//string str;
	//get_go_bounding_box_info(m_go, str);
	
	return GraphObjTool::OnMove();;
}
//----- end MOVE_DATA_DISPLAY_CODE_TO_BASE_CLASS

// return < 0 if no preview graph, 1 = initial show, 0 = already shown 
// this function will always check and create wks if has been deleted by user
int GraphObjCurveTool::CheckShowPreview()
{	
	if(m_strPreviewGraphName.IsEmpty())
		m_strPreviewGraphName = m_strGraphTemplate;

	if(m_strPreviewGraphName.IsEmpty())
		return -1; // pewview graph not needed
	
	ASSERT(!m_strPreviewDataWksName.IsEmpty());// for now, assume wks based, so with a graph, must have wks
	
	int nRet = 0;
	if(!m_glPreview)
	{
		GraphPage gp(m_strPreviewGraphName);
		if(!gp)
		{	
	   		gp.Create(m_strGraphTemplate);
	   		gp.SetName(m_strPreviewGraphName);
	   		gp.SetLongName(m_strPreviewGraphLongName);
	   		m_glPreview = gp.Layers(0); 
	   		nRet = 1;
		}
		else
			m_glPreview = gp.Layers(0);
	}
	if(CheckPreviewDataWks() > 0)
		nRet = 1;
	return nRet;
}

/// Fisher 9/16/2008
// return < 0 if no preview graph, 1 = initial show, 0 = already shown 
int		GraphObjCurveTool::CheckPreviewDataWks(bool bCreate)// = true)
{
	if(m_strPreviewDataWksName.IsEmpty())
		return -1; 		// no temp data wks
	
	if(!m_wks)	// Need temp worksheet
	{
		//---- CPY 7/20/09 QA70-13575 HANDLE_RESCALE_EVENT_FOR_GRAPH_OBJ_TOOL
		//if(!m_wks.Attach(m_strPreviewDataWksName))
		if(!m_wks.Attach(m_strPreviewDataWksName) && bCreate)
		//----
		{
			WorksheetPage wp;
			wp.Create(NULL, CREATE_HIDDEN);
			wp.SetName(m_strPreviewDataWksName);
			wp.SetLongName(m_strPreviewDataWksLongName);
			m_wks = wp.Layers(0);
	   		return 1;
		}
	}

	return 0;
}

///---Sim 01-08-2010 QA81-14930 CLEAN_GRAPH_OBJ_TOOLS
/*
//---- CPY 9/27/08 CENTRALIZE_ADD_RECT_FOR_ALL_TOOLS
///Sophy 8/21/2009 QA80-14175 CREATE_ALL_NODES_IN_ONE_TREE_TO_GET_RID_OF_OPTIONS_BRANCH
//int GraphObjCurveTool::Create(LPCSTR lpcszXFName, int color, DWORD dwCntrl, const TreeNode& trGUI)
int GraphObjCurveTool::Create(LPCSTR lpcszXFName, DWORD dwCntrl, const TreeNode& trGUI)
///end CREATE_ALL_NODES_IN_ONE_TREE_TO_GET_RID_OF_OPTIONS_BRANCH
{
	GraphPage gp = Project.Pages();
	if(!gp)	
		return -1;
	
	GraphLayer gl = gp.Layers(); //Layers(0);CPY 9/24/08 QA70-92268 GR_SHOULD_ALLOW_ON_MULTI_LAYER_GRAPH
	if(!gl)
		return -2;
	
	GraphObject go;
	double x0 = 25, y0 = 25, x1 = 70, y1 = 70;
	///Sophy 8/21/2009 QA80-14175 CREATE_ALL_NODES_IN_ONE_TREE_TO_GET_RID_OF_OPTIONS_BRANCH
	//int nColor = SYSCOLOR_YELLOW;
	//if(color > 0)
		//nColor = okutil_ocolor_LT_color_convert(color, false);
	int nColor = trGUI.rectcolor.nVal;
	///end CREATE_ALL_NODES_IN_ONE_TREE_TO_GET_RID_OF_OPTIONS_BRANCH

	int nDirection = (dwCntrl & GCTC_FREE_FORM_RECT)? LN_FREE:LN_VERTICAL;

	if(add_rect(gl, go, x0, y0, x1, y1, nColor, ATTACH_TO_LAYER, nDirection, true))	//  ATTACH_TO_SCALE, LN_VERTICAL
	{
		if(Attach(go.GetName()))
		{
			if(trGUI != NULL)
			{
				if(!SetGUITree(trGUI))
					return 2;
	}
			if(!Init())
				return 3;
			//CPY 10/1/08 QA70-12321 ADD_LT_WAY_TO_FORCE_XF_COMPILE,
			//string strXFFunc; strXFFunc.Format("%s_events", lpcszXFName);
			string strLT;strLT.Format("run.section(graph_controls,GraphTool,%%1 %s)", lpcszXFName);
			set_LT_script(go, strLT, GRCT_ANY_EVENT, 1);
			
			///Sophy 8/26/2009 QA80-14169 MAKE_GRAPHOBJECT_FOR_PROGRAMMING_CONTROL_PRINTABLE
			MakePrintable(go); //if move this code before set_LT_script, will fail to make the rectangle printable, or lese we'll not need to virtual this function.
			///end MAKE_GRAPHOBJECT_FOR_PROGRAMMING_CONTROL_PRINTABLE
			
			///Sophy 1/5/2010 QA80-14904-S1 CLEAN_CODE_FOR_ROI_TOOLS
			CheckAttachObjs();
			///end CLEAN_CODE_FOR_ROI_TOOLS
			OnMove();
			return 0;
		}
	}
	return 1;
}
*/
int GraphObjCurveTool::Create(LPCSTR lpcszXFName, DWORD dwCntrl, const TreeNode& trGUI, int nROIShape/* = SHAPE_RECT*/)
{
	GraphPage gp = Project.Pages();
	if(!gp)	
		return -1;
	m_gp = gp;

	GraphLayer gl = gp.Layers(); //Layers(0);CPY 9/24/08 QA70-92268 GR_SHOULD_ALLOW_ON_MULTI_LAYER_GRAPH
	if(!gl)
		return -2;
	m_gl = gl;
	
	GraphObject go;
	double x0 = 25, y0 = 25, x1 = 70, y1 = 70;
	
	/// Iris 1/27/2010 ADD_LEFTX_RIGHTX_IN_ROI_TAB
	int nAttach = ATTACH_TO_LAYER;
	bool bPercent = true;
	double dLeftX, dRightX;
	bool bFixWidth; /// Iris 2/21/2010 REMOVE_AUTO_CHECKBOX_REPLACE_WITH_FIX_WIDTH_CHECKBOX
	/// Iris 2/21/2010 REMOVE_AUTO_CHECKBOX_REPLACE_WITH_FIX_WIDTH_CHECKBOX
	//if( CheckGetMainObjectXPositionFromGUITree(trGUI, dLeftX, dRightX) )
	///Sophy 3/5/2010 EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
	//if( CheckGetMainObjectXPositionFromGUITree(trGUI, dLeftX, dRightX, bFixWidth) )
	double dBottomY = y0, dTopY = y1;
	if( CheckGetMainObjectPositionFromGUITree(trGUI, dLeftX, dRightX, bFixWidth, dBottomY, dTopY) )
	///end EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
	///End REMOVE_AUTO_CHECKBOX_REPLACE_WITH_FIX_WIDTH_CHECKBOX
	{
		nAttach = ATTACH_TO_SCALE;
		bPercent = false; // replace percent by scale
		x0 = dLeftX;
		x1 = dRightX;
		///Sophy 3/5/2010 EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
		y0 = dBottomY;
		y1 = dTopY;
		///end EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
	}	
	///End ADD_LEFTX_RIGHTX_IN_ROI_TAB
	
	///Sophy 8/21/2009 QA80-14175 CREATE_ALL_NODES_IN_ONE_TREE_TO_GET_RID_OF_OPTIONS_BRANCH
	//int nColor = SYSCOLOR_YELLOW;
	//if(color > 0)
		//nColor = okutil_ocolor_LT_color_convert(colr, false);
	
	///Sophy 1/18/2010 CLEAN_CODE_SUPPORT_FLEXIBLE_COLOR_SETTING_ACCESS
	//int nColor = trGUI.rectcolor.nVal;
	int nColor = SYSCOLOR_YELLOW;
	TreeNode trColor = GetFillColorNode(trGUI);
	if ( trColor )
		nColor = trColor.nVal;
	///end CLEAN_CODE_SUPPORT_FLEXIBLE_COLOR_SETTING_ACCESS
	///end CREATE_ALL_NODES_IN_ONE_TREE_TO_GET_RID_OF_OPTIONS_BRANCH
	
	///Sophy 2/10/2010 QA81-15097 ROI_TOOLS_DONT_WORK_WHEN_XY_AXIS_EXCHANGED
	//int nDirection = (dwCntrl & GCTC_FREE_FORM_RECT)? LN_FREE:LN_VERTICAL;
	int nDirection = (dwCntrl & GCTC_FREE_FORM_RECT) ? LN_FREE : (is_active_graphlayer_xyexchanged() ? LN_HORIZONTAL : LN_VERTICAL);
	///end ROI_TOOLS_DONT_WORK_WHEN_XY_AXIS_EXCHANGED
				
	/// Iris 1/27/2010 ADD_LEFTX_RIGHTX_IN_ROI_TAB
	//if(add_rect(gl, go, x0, y0, x1, y1, nColor, ATTACH_TO_LAYER, nDirection, true))	//  ATTACH_TO_SCALE, LN_VERTICAL
	///Sophy 3/4/2010 EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
	//if(add_rect(gl, go, x0, y0, x1, y1, nColor, nAttach, nDirection, true, bPercent))	//  ATTACH_TO_SCALE, LN_VERTICAL
	bool bROICreated = false;
	if ( SHAPE_RECT == nROIShape )
		bROICreated = add_rect(gl, go, x0, y0, x1, y1, nColor, nAttach, nDirection, true, bPercent);
	else if ( SHAPE_CIRCLE == nROIShape )
	{
		//bROICreated = add_ellipse(gl, go, x0, y0, x1, y1, nColor, nAttach, bPercent);
		bROICreated = add_circle(gl, go, (x0 + x1)/2, (y0 + y1)/2, (x1 - x0)/2, (y1 - y0)/2, nColor, SYSCOLOR_LTYELLOW, nAttach, bPercent);
		go.Width = go.Height; //make it like a circle.
	}
	if ( bROICreated )
	///end EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
	///End ADD_LEFTX_RIGHTX_IN_ROI_TAB
	{
		if(Attach(go.GetName()))
		{
			set_go_behind_data(go);
			//set_go_user_deleteable(m_go, true);CPY 9/23/08 this is now done as part of set_LT_script

			/// YuI 09/24/08 QA70-12264 OPTION_TO_SELECT_GR_OBJECT_BEFORE_DATA
			set_go_hittest_before_data(go);
			/// end OPTION_TO_SELECT_GR_OBJECT_BEFORE_DATA

			//CPY 10/1/08 QA70-12321 ADD_LT_WAY_TO_FORCE_XF_COMPILE,
			//string strXFFunc; strXFFunc.Format("%s_events", lpcszXFName);
			string strLT;strLT.Format("run.section(graph_controls,GraphTool,%%1 %s)", lpcszXFName);
			set_LT_script(go, strLT, GRCT_ANY_EVENT, 1);
			///Sophy 1/22/2010 QA80-14996 GR_OBJ_NEED_MOVE_EVENT_WHEN_UNDO_MOVE_OPERATION_FOR_QUICK_FIT
			strLT.Format("%s.UndoEvent=1;", go.GetName());
			LT_execute(strLT);
			///end GR_OBJ_NEED_MOVE_EVENT_WHEN_UNDO_MOVE_OPERATION_FOR_QUICK_FIT
			///Sophy 01/23/10 QA80-15015 GROBJ_NEED_OPTION_CTRL_DELETE_OPERATION_UNDOABLE_OR_NOT
			strLT.Format("%s.DelUndoable=0;", go.GetName());
			LT_execute(strLT);
			///end GROBJ_NEED_OPTION_CTRL_DELETE_OPERATION_UNDOABLE_OR_NOT
	
			///Sophy 8/26/2009 QA80-14169 MAKE_GRAPHOBJECT_FOR_PROGRAMMING_CONTROL_PRINTABLE
			MakePrintable(go); //if move this code before set_LT_script, will fail to make the rectangle printable, or lese we'll not need to virtual this function.
			///end MAKE_GRAPHOBJECT_FOR_PROGRAMMING_CONTROL_PRINTABLE
	
			referenceCount(true);//---- CPY 9/26/08 QA70-12266 ADDTOOL_XF_NEEDS_PROJ_VAR_TO_INDICATE_THEY_ARE_STILL_ACTIVE
	
			if(trGUI != NULL)
			{
				///------ Folger 02/01/10 CURRENT_THEME_NAME_SHOULD_SHOW_WHEN_SAVE_THEME_AS_IN_ROI_TOOLS
				UpdateThemeFileInGUITree(trGUI);
				///------ End CURRENT_THEME_NAME_SHOULD_SHOW_WHEN_SAVE_THEME_AS_IN_ROI_TOOLS
				if(!SetGUITree(trGUI))
					return 2;
			}
			
			///Sophy 1/5/2010 QA80-14904-S1 CLEAN_CODE_FOR_ROI_TOOLS
			//CheckAttachObjs();
			if ( 0 != CreateAttachments() )
				return 3;
			
			if ( 0 != GetAttachments() )
				return 4;
			///end CLEAN_CODE_FOR_ROI_TOOLS			
			SetVersion();	///Sophy 2/4/2010 QA80-15080 VERSION_CHECKING_FOR_ROI_COMPATIBILITY	
			
			set_ROI_main_obj_name(m_gl, GetXFName(), m_go.GetName()); ///Sophy 3/8/2010 EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
			/// Iris 2/21/2010 REMOVE_AUTO_CHECKBOX_REPLACE_WITH_FIX_WIDTH_CHECKBOX
			//OnMove();
			if( bFixWidth )
			{
				disable_go_move(go);
			}
			///End REMOVE_AUTO_CHECKBOX_REPLACE_WITH_FIX_WIDTH_CHECKBOX
			///Sophy 4/29/2010 ORG-59 REGION_STATS_GADGET_SHOULD_SEL_ALL_PLOTS_BY_DEFAULT
			SetMultiPlotsState(true); //this will apply to all ROI tools that support selecting all curves, if other tools in the future do NOT want thsi logic, need to virtual a new function IsSelAllPlotsOnStats or something like this.
			///end REGION_STATS_GADGET_SHOULD_SEL_ALL_PLOTS_BY_DEFAULT
			OnMove();
			
			return 0;
		}
	}
	return 1;
}

///------ Folger 02/01/10 CURRENT_THEME_NAME_SHOULD_SHOW_WHEN_SAVE_THEME_AS_IN_ROI_TOOLS
void	GraphObjCurveTool::UpdateThemeFileInGUITree(TreeNode& trGUI)
{
	XFExeContext*	pXFExecCtxt = Project.GetCurrentXFExeCtxt();
	if ( pXFExecCtxt )
	{
		Tree		tr;
		TreeNode	trGetN;
		if ( pXFExecCtxt->GetGUI(tr, trGetN) )
		{
			tree_node_copy_attribute(trGetN, trGUI, STR_THEME_FILE_ATTRIB);
			UpdateBranchIDs(trGetN, trGUI);///Sophy 2/5/2010 FAIL_TO_LOAD_THEME_WITH_DUPLICATED_IDS

		}
	}
	else
	{
		///Sophy 3/4/2010 EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL when debug is turn on and popup a message box, will affect the execution of ";label -rc Rect"
		//ASSERT(FALSE);
		///end EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
	}
}

string	GraphObjCurveTool::GetCurrentThemeName()
{
	Tree	trGUI;
	if ( GetGUITree(trGUI) )
	{
		string		strThemeFile;
		if ( trGUI.GetAttribute(STR_THEME_FILE_ATTRIB, strThemeFile) )
			return okutil_theme_file_to_display_name(strThemeFile);
	}

	return "";
}

///Sophy 2/5/2010 FAIL_TO_LOAD_THEME_WITH_DUPLICATED_IDS
//virtual
bool	GraphObjCurveTool::UpdateBranchIDs(TreeNode& trGetN, TreeNode& trGUI)
{
	TreeNode trGetNGUI = trGetN.trGUI;
	if ( trGetNGUI && trGUI )
	{
		int nDataID, nRepeatID;
		if ( trGetNGUI.GetAttribute(STR_DATAID_ATTRIB, nDataID) && trGetNGUI.GetAttribute(STR_REPEAT_ID_ATTRIB, nRepeatID) )
		{
			trGUI.SetAttribute(STR_DATAID_ATTRIB, nDataID);
			trGUI.SetAttribute(STR_REPEAT_ID_ATTRIB, nRepeatID);
			return true;
		}
		ASSERT(FALSE); //never come here.
		return false;
	}
	return false;
}
///end FAIL_TO_LOAD_THEME_WITH_DUPLICATED_IDS

/// virtual
bool	GraphObjCurveTool::UpdateThemeTree(TreeNode& trThemeTree)
{
	if ( !trThemeTree )
		return false;

	///Sophy 2/5/2010 FAIL_TO_LOAD_THEME_WITH_DUPLICATED_ID
	TreeNode trResults = trThemeTree.Results;
	if ( trResults )
		trResults.Remove();
	///end FAIL_TO_LOAD_THEME_WITH_DUPLICATED_ID
	
	string		strTheme = GetCurrentThemeName();
	if ( !strTheme.IsEmpty() && !IS_THEME_WITH_ORDER(strTheme) && theme_is_valid_name_for_save_as(strTheme) )
		trThemeTree.SetAttribute(STR_DEFAULT_THEME_NAME, strTheme);
	
	return true;
}
///------ End CURRENT_THEME_NAME_SHOULD_SHOW_WHEN_SAVE_THEME_AS_IN_ROI_TOOLS

int	GraphObjCurveTool::CreateAttachments()
{
	int nRet = GraphObjTool::CreateAttachments();
	if ( 0 != nRet )
		return nRet;
	
	for ( int ii = 0; ii < m_vnObjIDs.GetSize(); ii++ )
	{
		string strScript;
		switch ( m_vnObjIDs[ii] )
		{
		case GOT_OBJ_LABEL:
			CreateAttachment(m_goLabel, m_vnObjIDs[ii], CTP_TOP, GROBJ_TN_TEXT, "No Data Selected");
			///Sophy 2/12/2010 MORE_CLEAN_CODE_TO_RESET_LABEL_POSITION
			roi_tool_option_access(ROI_OPTION_RESET_LABEL_POS, ROI_OP_SET); //force reset position when init its contents.
			///end MORE_CLEAN_CODE_TO_RESET_LABEL_POSITION
			break;
			
		case GOT_OBJ_CONTEXT:
			CreateAttachment(m_goContext, m_vnObjIDs[ii], CTP_RIGHT_TOP, GROT_TEXT, "\z(12)");
			strScript.Format("run.section(graph_controls, GraphToolEvent, %s %s %d %d);", GetXFName(), m_go.GetName(), OE_BUTTONCLICK, GOT_BTN_CONTEXT);
			set_LT_script(m_goContext, strScript, GRCT_MOUSEUP, 1);
			break;
		}
	}
	CheckUpdateToolName();	///Sophy 1/19/2010 QA80-14832 SHOW_TOOLNAME_FOR_ROI_TOOLS
	return 0;
}

//virtual
int	GraphObjCurveTool::GetAttachments()
{
	int nRet = GraphObjTool::GetAttachments();
	if ( 0 != nRet )
		return nRet;
	
	nRet = GetAttachment(m_goLabel, GOT_OBJ_LABEL);
	if ( 0 != nRet )
		return nRet;
	
	nRet = GetAttachment(m_goContext, GOT_OBJ_CONTEXT);
	if  ( 0 != nRet )
		return nRet;
	
	return 0;
}


//virtual
void	GraphObjCurveTool::OnEvent(int nEvent, int nMsg)
{
	if ( QUERY_ROI_TOOL_OPTION(ROI_OPTION_IGNORE_EVENT) )
		return;
	
	switch(nEvent)
	{
	case OE_BUTTONCLICK:
		switch(nMsg)
		{
		//case GOT_BTN_PLOTS:
			//DoShowPlots();
			//break;
		//case GOT_BTN_OUTPUT:
			//DoOutput();
			//break;
		//case GOT_BTN_EDIT:
			//DoEdit();
			//break;
			//
		//case GOT_BTN_FUNCTION:
			//DoFunction();
			//break;
			
		case GOT_BTN_CONTEXT:
			//DoContext();
			ROI_DELAY_EXECUTE_EX(ROI_OPTION_DO_CONTEXT, OE_BUTTONCLICK, DoContext(), GOT_BTN_CONTEXT);
			break;
			
		///Sophy 6/13/2010 ORG-23-S5 SHOW_APPLY_BUTTON_FOR_INTERP_PREFERENCE_DLG
		case GOT_BTN_APPLY:
			UpdateROIGUI();
			break;
			
		default:
			out_int("Unknown button clicked. ID = ", nMsg);
			break;
		///end SHOW_APPLY_BUTTON_FOR_INTERP_PREFERENCE_DLG

		}
	default:
		//out_int("other even = ", nEvent);
	}
	if ( OE_RESIZE == nEvent || OE_SCALE_CHANGE == nEvent )
		UpdateInnerAttachments();
	
	if ( nEvent == 500 )
	{
		Tree trGUI;
		GetGUITree(trGUI);
	}
	GraphObjTool::OnEvent(nEvent, nMsg);
}

///---END QA81-14930 CLEAN_GRAPH_OBJ_TOOLS

///Sophy 1/5/2010 QA80-14904-S1 CLEAN_CODE_FOR_ROI_TOOLS
//bool	GraphObjCurveTool::CheckAttachObjs()
//{
	//CreateAdvancedButtons(GetXFName());
	//return true;
//}

///Sophy 1/22/2010 CENTRALIZE_OPEN_PREFERENCE_DIALOG_TO_BASE_CLASS
//since most ROI tool based on GetN have similar code to change parameter, I move it to base class, but still allow derived class to overwrite it as to do their own things.
//virtaul
bool	GraphObjCurveTool::DoEdit(HWND hWndParent/* = NULL*/)
{
	Tree trGUI;
	if ( !GetGUITree(trGUI) )
		return false;
	
	GETN_TREE(tr)
	tr.Replace(trGUI, true, true, false);
	
	tr.SetAttribute(STR_CLASS_OPTION_NAME_ATTRIB, GetXFName());
	string strTitle;
	strTitle.Format("%s %s", GetPreferenceTitle(), STR_PREFERENCES);
	///Sophy 6/10/2010 ORG-48-P14 BETTER_EVENT_HANDLE_FOR_PREFERENCE_IN_ROI_TOOLS
	//if ( GetNBox(tr, NULL, strTitle, "", hWndParent) )
	TreeNode trEvt = tr.GetNode(STR_EVENT_HANDLE);
	GET_GETN_EVT(trEvt, pfnEvt)
	///Sophy 6/13/2010 ORG-23-S5 SHOW_APPLY_BUTTON_FOR_INTERP_PREFERENCE_DLG
	TreeNode trAppEvt = tr.GetNode(STR_APPLY_EVT);
	GET_APPLY_EVT(trAppEvt, pfnAppEvt);
	bool bShowAppBtn = pfnAppEvt != NULL;
	///end SHOW_APPLY_BUTTON_FOR_INTERP_PREFERENCE_DLG
	if ( GetNBox(tr, pfnEvt, strTitle, "", hWndParent, bShowAppBtn, pfnAppEvt) )
	///end BETTER_EVENT_HANDLE_FOR_PREFERENCE_IN_ROI_TOOLS
	{
		roi_tool_option_access(ROI_OPTION_RESET_LABEL_POS, ROI_OP_SET);	///Sophy 2/2/2010 RESET_TOP_LABEL_POS_WHEN_CHANGE_FUNC_OR_PREFERENCES
		///------ Folger 02/04/10 SUPPORT_LOAD_THEME_IN_ROI_TOOLS_CONTEXT_MENU
		//UpdateMainRect(tr);
		//SetGUITree(tr);
		//SetResultsTree(NULL);
		//OnMove();
		SetGUITree(tr);
		UpdateROIGUI();
		///------ End SUPPORT_LOAD_THEME_IN_ROI_TOOLS_CONTEXT_MENU
		return true;
	}
	return true;
}
///end CENTRALIZE_OPEN_PREFERENCE_DIALOG_TO_BASE_CLASS
bool	GraphObjCurveTool::DoContext()
{
	//---- CPY 2/2/10 CONTEXT_MENU_POPUP_POSITION_MAKE_CONSISTENT
	//POINT pt;
	//GetCursorPos(&pt);
	//----
	
	uint nCurItemPos = 0;
	Menu pm;	
	pm.Add(STR_DO_OUTPUT, GOT_BTN_OUTPUT); nCurItemPos++;
	AddUpdateLastOutputSubmenu(pm, nCurItemPos); /// Iris 2/20/2010 MOVE_REPLACE_LAST_OUTPUT_TO_CONTEXT_MENU
	AddGotoReport(pm, nCurItemPos);
	pm.Add(NULL, 0, MF_SEPARATOR); nCurItemPos++;
	
	AddPlots(pm, nCurItemPos);
	pm.Add(STR_EXPAND_AREA, GOT_BTN_EXPAND, MF_STRING | (IsExpandable() ? 0 : MF_GRAYED)); nCurItemPos++;
	UpdateContextMenu(pm, nCurItemPos);
	pm.Add(NULL, 0, MF_SEPARATOR); nCurItemPos++;
	AddDataEdit(pm, nCurItemPos); ///Sophy 3/8/2010 EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
	pm.Add(STR_SAVE_THEME, GOT_BTN_SAVE_THEME);	nCurItemPos++; ///Sophy 1/19/2010 QA80-14832 ADD_SAVE_THEME_AS_IN_CONTEXT_MENU_FOR_ROI_TOOLS
	///------ Folger 02/04/10 SUPPORT_LOAD_THEME_IN_ROI_TOOLS_CONTEXT_MENU
	AddThemes(pm);
	///------ End SUPPORT_LOAD_THEME_IN_ROI_TOOLS_CONTEXT_MENU
	pm.Add(STR_DO_EDIT, GOT_BTN_EDIT); nCurItemPos++;
	
	int nCmdID;
	//---- CPY 2/2/10 QA81-15066 CONTEXT_MENU_POPUP_POSITION_MAKE_CONSISTENT
	//int XAdj = m_goContext.Width * 0.1, YAdj = m_goContext.Height * 0.07;
	//pm.TrackPopupMenu(TPM_LEFTBUTTON | TPM_LEFTALIGN  , pt.x + XAdj, pt.y - YAdj, GetWindow(), &nCmdID);
	int nx = m_goContext.Left + m_goContext.Width;
	int ny = m_goContext.Top;
	
	nx += m_goContext.Width * 0.4;	///Sophy 2/3/2010 CONTEXT_MENU_POPUP_POSITION_MAKE_CONSISTENT add a gap for better view
	m_gp.LPtoDP(nx, ny);
	
	Window wnd = m_gp.GetWindow();
	RECT rr;
	rr.left = rr.right = nx;
	rr.top = rr.bottom = ny;
	wnd.ClientToScreen(&rr);
	pm.TrackPopupMenu(TPM_LEFTBUTTON | TPM_LEFTALIGN, rr.left, rr.top, wnd.GetSafeHwnd(), &nCmdID);
	//---- end CONTEXT_MENU_POPUP_POSITION_MAKE_CONSISTENT
	if ( nCmdID != 0 )
	{
		DWORD dwHigher = GOT_BTN_FIXED_MASK & nCmdID;
		if ( 0 == dwHigher )
		{
			switch(nCmdID)
			{
			case GOT_BTN_OUTPUT:
				/// Iris 2/20/2010 MOVE_REPLACE_LAST_OUTPUT_TO_CONTEXT_MENU
				//DoOutput();
				if ( DoOutput(false) )
				{
					checkCloneMainObj();	///Sophy 3/19/2010 QA81-15217 CLONE_MAIN_OBJ_ON_OUTPUT_FOR_ROI_TOOLS
				}
				///End MOVE_REPLACE_LAST_OUTPUT_TO_CONTEXT_MENU
				break;
				
			case GOT_BTN_EDIT:
				DoEdit();				
				break;
				
			case GOT_BTN_EXPAND:
				DoExpand();
				break;
				
			case GOT_BTN_FIT:
				DoFit();
				break;
				
			case GOT_BTN_FINDXY:
				DoFindXY();
				break;
				
			///Sophy 1/15/2010 ADD_EDIT_FUNCTION_LIST_IN_CONTEXT_MENU_FOR_QUICKFIT_ROI
			case GOT_BTN_UPDATE_LIST:
				DoUpdateList();
				break;
			///end ADD_EDIT_FUNCTION_LIST_IN_CONTEXT_MENU_FOR_QUICKFIT_ROI
				
			///Sophy 1/19/2010 QA80-14832 ADD_SAVE_THEME_AS_IN_CONTEXT_MENU_FOR_ROI_TOOLS
			case GOT_BTN_SAVE_THEME:
				DoSaveTheme();
				break;
			///end ADD_SAVE_THEME_AS_IN_CONTEXT_MENU_FOR_ROI_TOOLS
			
			///Sophy 1/26/2010 ADD_GO_TO_REPORT_TABLE_MENU_IN_CONTEXT
			case GOT_BTN_GOTO_REPORT:
				DoActiveReport();
				break;
			///end ADD_GO_TO_REPORT_TABLE_MENU_IN_CONTEXT
			
			/// Iris 2/20/2010 MOVE_REPLACE_LAST_OUTPUT_TO_CONTEXT_MENU
			case GOT_BTN_UPDATE_LAST_OUTPUT:
				if ( DoOutput(true) )
				{
					updateLastCloneObjs();	///Sophy 3/19/2010 QA81-15217 CLONE_MAIN_OBJ_ON_OUTPUT_FOR_ROI_TOOLS
				}
				break;
			///End MOVE_REPLACE_LAST_OUTPUT_TO_CONTEXT_MENU
				
			///Sophy 3/8/2010 EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
			case GOT_BTN_SEL_ALL_PLOTS:
				DoSelAllPlots();
				OnMove();
				break;
				
			case GOT_BTN_DATA_EDIT:
				DoEditData();
				OnMove();	///Sophy 6/11/2010 ORG-25-P3 UPDATE_RESULT_DIALOG_AFTER_EDIT_POINTS
				break;
			///end EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
			default:
				ASSERT(false);
				break;
			}
		}
		else
		{
			int	nIndex = (GOT_BTN_FLEX_MASK & nCmdID) - 1;
			switch(dwHigher)
			{
			case GOT_BTN_PLOTS:
				///Sophy 3/8/2010 EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
				//SetPlot(nIndex);
				OnSetPlot(nIndex);
				///end EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
				/// Kenny 03/05/2010 QA81-14832 QUICK_FIT_WRONG_AUTO_PREVIEW_FITTED_CURVE_COLOR
				OnPlotChanged();
				/// End QA81-14832 QUICK_FIT_WRONG_AUTO_PREVIEW_FITTED_CURVE_COLOR
				break;
			case GOT_BTN_FUNCTION:
				SetFunction(nIndex);
				break;
			///------ Folger 02/04/10 SUPPORT_LOAD_THEME_IN_ROI_TOOLS_CONTEXT_MENU
			case GOT_BTN_THEMES:
				{
					vector<string>		vsThemes;
					vector<string>		vsFiles;
					int					nCount = okutil_theme_get_class_settings(GetXFName(), &vsFiles, &vsThemes, THTYPE_ANALYSIS, TRUE, TRUE);
					ASSERT(nIndex < nCount);

					///Sophy 2/11/2010 FAIL_TO_LOAD_THEME_WITH_DUPLICATED_IDS
					//theme_load_settings(trGUI, vsFiles[nIndex]);
					Tree	tr;
					GetTree(tr);
					tr.RemoveChild("Results");
					///Sophy 6/8/2010 ORG-48-P9 FAIL_TO_DEFAUL_THEME_FROM_CONTEXT_MENU
					//theme_load_settings(tr, vsFiles[nIndex], false);
					theme_update_on_new_sel(tr, vsThemes[nIndex]);
					///end FAIL_TO_DEFAUL_THEME_FROM_CONTEXT_MENU
					SetTree(tr);
					roi_tool_option_access(ROI_OPTION_RESET_LABEL_POS, ROI_OP_SET); //need to reset label position since top label parameters may changes.
					///end FAIL_TO_LOAD_THEME_WITH_DUPLICATED_IDS
					Tree	trGUI;
					GetGUITree(trGUI);
					trGUI.SetAttribute(STR_THEME_FILE_ATTRIB, vsFiles[nIndex]);
					UpdateGUIOnThemeChange(trGUI);
					SetGUITree(trGUI);
					UpdateROIGUI();
					return true;
				}
				break;
			///------ End SUPPORT_LOAD_THEME_IN_ROI_TOOLS_CONTEXT_MENU

			///Kyle 03/08/2010 CUSTOM_CMD_IN_CONTEXT_MENU_OF_GRAPH_OBJ_TOOLS
			case GOT_CMD_CUSTOM:
				{
					OnCmdCustom(nCmdID);
				}
				break;
			///End CUSTOM_CMD_IN_CONTEXT_MENU_OF_GRAPH_OBJ_TOOLS
			default:
				ASSERT(false);
				break;
			}
			OnMove(); //update result
		}
	}
	return true;
}

bool	GraphObjCurveTool::RemoveMenu(Menu& pm, uint& nPosition, uint nDeletePos) //0
{
	if ( 0 <= nDeletePos && nDeletePos <= nPosition && pm && pm.RemoveMenu(nDeletePos, MF_BYPOSITION) )
	{
		nPosition--;
		return TRUE;
	}
	return FALSE;
}
///Sophy 1/23/2010 MAKE_QUICK_CURVE_STATS_AS_STANDARD_ROI_TOOL
bool	GraphObjCurveTool::UpdateTopLabel(LPCSTR lpcszText, bool bShow) //true
{
	if ( !m_goLabel )
		return false;
	
	if ( NULL != lpcszText )
		m_goLabel.Text = lpcszText;

	///Sophy 2/2/2010 RESET_TOP_LABEL_POS_WHEN_CHANGE_FUNC_OR_PREFERENCES
	if ( QUERY_ROI_TOOL_OPTION(ROI_OPTION_RESET_LABEL_POS) )
	{
		m_goLabel.Left = m_go.Left + (m_go.Width - m_goLabel.Width) / 2;
		m_goLabel.Top = m_go.Top - m_goLabel.Height;
		roi_tool_option_access(ROI_OPTION_RESET_LABEL_POS, ROI_OP_REMOVE);
	}
	///end RESET_TOP_LABEL_POS_WHEN_CHANGE_FUNC_OR_PREFERENCES
	m_goLabel.Show(bShow);
	return true;
}
///end MAKE_QUICK_CURVE_STATS_AS_STANDARD_ROI_TOOL

///Sophy 4/12/2010 QA81-15290 LABELS_INSIDE_ROI_SHOULD_NOT_BE_WHITEOUT
bool	GraphObjCurveTool::SetLabelTransparent(GraphObject& goLabel)
{
	if ( !goLabel )
		return false;
	Tree trFormat;
	trFormat.Root.TextWhiteOut.nVal = 0;
	int nErr = goLabel.UpdateThemeIDs(trFormat.Root);
	if ( nErr != 0 )
		return false;
	return goLabel.ApplyFormat(trFormat, true, true);
}
///end LABELS_INSIDE_ROI_SHOULD_NOT_BE_WHITEOUT
///Sophy 1/26/2010 ADD_GO_TO_REPORT_TABLE_MENU_IN_CONTEXT
bool	GraphObjCurveTool::AddGotoReport(Menu& pm, uint& nPosition)
{	
	DWORD dwFlags = MF_STRING;
	Worksheet wks;
	if ( !GetReportWorksheet(wks) )
		dwFlags |= MF_GRAYED;
	pm.Add(STR_GOTO_REPORT, GOT_BTN_GOTO_REPORT, dwFlags); nPosition++;
	return true;	
}
///end ADD_GO_TO_REPORT_TABLE_MENU_IN_CONTEXT

///Sophy 1/27/2010 FILTER_UNSUITABLE_PLOTTYPE_IN_CONTEXT_MENU
static	bool	_is_plot_suitable_for_ROI(int nPlotType)
{
	if ( nPlotType > IDM_PLOT_DOT || nPlotType < IDM_PLOT_LINE )
		return false;
	//Sophy if any other type not suitable for ROI, need to add more cases below.
	
	return true;
}
///end FILTER_UNSUITABLE_PLOTTYPE_IN_CONTEXT_MENU
int		GraphObjCurveTool::AddPlots(Menu& pm, uint& nPosition)
{
	/// Iris 2/20/2010 MOVE_REPLACE_LAST_OUTPUT_TO_CONTEXT_MENU
	/*
	int nCurPlotIndex = -1;
	Tree trInfo;
	if ( tree_get_binary_storage(trInfo, m_go, ATTACHED_GRAPH_OBJECTS_INFO) && trInfo.curPlotIndex )
	{
		nCurPlotIndex = trInfo.curPlotIndex.nVal;
	}
	else
		nCurPlotIndex = m_gl.DataPlots().GetIndex();
	*/	
	int nCurPlotIndex = -1;
	DataPlot dpActive;
	if( GetSelectedPlot(dpActive) )
		nCurPlotIndex = dpActive.GetIndex();
	///End MOVE_REPLACE_LAST_OUTPUT_TO_CONTEXT_MENU
	
	Menu subMenu;
	string strLabel;
	vector<int> vI1;
	vector<int> vI2;
	//DataPlot dpActive = m_gl.DataPlots(nCurPlotIndex); /// Iris 2/20/2010 MOVE_REPLACE_LAST_OUTPUT_TO_CONTEXT_MENU
	if ( dpActive && dpActive.GetDataRegions(m_go, vI1, vI2) <= 0 )
	{
		nCurPlotIndex = -1;
	}
	
	vector<string>	vsItems(0);
	vector<int>		vnCmdIDs(0);
	XYRange xySrc;
	Column colY;
	foreach(DataPlot dp in m_gl.DataPlots)
	{
		if ( IsPlotForROI(dp) )
		{
			if ( nCurPlotIndex < 0 ) //if previously active plot is not in region, should set another one as active
			{
				nCurPlotIndex = dp.GetIndex();
				/// Iris 2/20/2010 MOVE_REPLACE_LAST_OUTPUT_TO_CONTEXT_MENU
				/*
				trInfo.curPlotIndex.nVal = nCurPlotIndex;
				tree_put_binary_storage(trInfo, m_go, ATTACHED_GRAPH_OBJECTS_INFO);
				*/
				SetPlot(nCurPlotIndex);
				///End MOVE_REPLACE_LAST_OUTPUT_TO_CONTEXT_MENU
			}
			
			string strName;
			///Sophy 2/3/2010 ROI_CONTEXT_MENU_DATAPLOT_SHOW_LEGEND_AS_IN_NLFIT
			//dp.GetRangeString(strName, NTYPE_SHORT_NAME_ONLY | NTYPE_BOOKSHEET_XY_RANGE | NTYPE_ADD_ROW_RANGE);
			dp.GetLegend(strName);
			///end ROI_CONTEXT_MENU_DATAPLOT_SHOW_LEGEND_AS_IN_NLFIT
			strLabel.Format("Plot(%d)\t%s", dp.GetIndex() + 1, strName);
			vsItems.Add(strLabel);
			vnCmdIDs.Add(GOT_BTN_PLOTS | (dp.GetIndex() + 1));
		}
	}
	if ( vsItems.GetSize() > 1 )
	{
		uint nPosition = 0;
		for ( int iItem = 0; iItem < vsItems.GetSize(); iItem++ )
		{
			DWORD dwFlag = MF_STRING;
			if ( !GetMultiPlotsState() )
			{
				if ( vnCmdIDs[iItem] == (GOT_BTN_PLOTS | (nCurPlotIndex + 1)) ) //current plot
					dwFlag |= MF_CHECKED;
			}
				
			subMenu.Add(vsItems[iItem], vnCmdIDs[iItem], dwFlag); nPosition++;
		}
		///Sophy 3/8/2010 EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
		UpdatePlotsMenu(subMenu, nPosition);
		///end EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
	}
	else if ( vsItems.GetSize() == 1 )
		subMenu.Add(vsItems[0], vnCmdIDs[0], MF_STRING | MF_GRAYED | MF_CHECKED);
	
	if ( vsItems.GetSize() > 0 )
	{
		pm.AddPopup(STR_SHOW_PLOTS, subMenu, GOT_BTN_PLOTS);
		nPosition++;
	}
	return 0;
}

///Sophy 3/8/2010 EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
//virtual
bool	GraphObjCurveTool::IsPlotForROI(const DataPlot& dp)
{
	///Kyle 03/15/2010 IS_PLOT_FOR_ROI_GIVE_OPTION_TO_SPECIFY_THE_NAME_TO_TAG_A_DATAOBJ
	//return is_plot_for_ROI(dp, m_go);
	return is_plot_for_ROI(dp, m_go, STR_DATASETOBJ_FITCURVE);
	///End IS_PLOT_FOR_ROI_GIVE_OPTION_TO_SPECIFY_THE_NAME_TO_TAG_A_DATAOBJ
}
//virtual
bool	GraphObjCurveTool::UpdatePlotsMenu(Menu& pm, uint& nPosition)
{
	if ( pm && IsSupportMultiPlots() )
	{
		if ( m_gl.DataPlots.Count() <= 1 ) //only one plot
			return false;
		pm.Add(NULL, 0, MF_SEPARATOR); nPosition++;
		DWORD dwFlag = MF_STRING;
		if ( GetMultiPlotsState() )
			dwFlag |= MF_CHECKED;
		pm.Add(_L("All Plots"), GOT_BTN_SEL_ALL_PLOTS, dwFlag); nPosition++;
		return true;
	}
	return false;
}

bool	GraphObjCurveTool::DoSelAllPlots()
{
	//return SetMultiPlotsState(!GetMultiPlotsState());
	if ( !GetMultiPlotsState() )
		SetMultiPlotsState(true);
	return true;
}

bool	GraphObjCurveTool::GetMultiPlotsState()
{
	if ( !IsSupportMultiPlots() )
		return false;
	Tree trInfo;
	if ( tree_get_binary_storage(trInfo, m_go, ATTACHED_GRAPH_OBJECTS_INFO) && trInfo.allPlots )
	{
		int nState = trInfo.allPlots.nVal;
		return (1 == nState);
	}
	return false;
}

bool	GraphObjCurveTool::SetMultiPlotsState(bool bOn)
{
	if ( !IsSupportMultiPlots() )
		return false;
	int nState = bOn ? 1 : 0;
	Tree trInfo;
	tree_get_binary_storage(trInfo, m_go, ATTACHED_GRAPH_OBJECTS_INFO);
	trInfo.allPlots.nVal = nState;
	tree_put_binary_storage(trInfo, m_go, ATTACHED_GRAPH_OBJECTS_INFO);
	return true;
}

bool	GraphObjCurveTool::AddDataEdit(Menu& pm, uint& nPosition)
{
	if ( pm && IsSupportEditData() )
	{
		pm.Add(_L("Edit Data Points..."), GOT_BTN_DATA_EDIT, MF_STRING); nPosition++;
		pm.Add(NULL, 0, MF_SEPARATOR); nPosition++;
		return true;
	}
	return false;
}

enum {
	DATA_DELETE_ROW = 0,
	DATA_MASK,
	DATA_CLEAR,
	DATA_ZERO,
	DATA_SET_VALUE,
};
#define	DATA_OP_LIST	_L("Delete Whole Row|Apply Mask|Clear|Set to 0|Set as")
enum {
	DATA_INNER_PTS = 0,
	DATA_OUTER_PTS = 1,
};
#define	DATA_REGION		_L("Inner Points|Outer Points")

static	bool	_on_operation_change(TreeNode& tr, int nRow, int nType, Dialog& Dlg)
{
	int nOp = tr.opera.nVal;
	tr.value.Show = (DATA_SET_VALUE == nOp);
	return true;
}
bool	GraphObjCurveTool::DoEditData(HWND hWndParent/* = NULL*/)
{
	int nUserID = GET_USER_DATAID(0);
	GETN_TREE(tr)
	GETN_LIST(opera, _L("Data Points Operation"), 0, DATA_OP_LIST)	GETN_ID(nUserID++)	GETN_OPTION_EVENT(_on_operation_change)
	GETN_NUM(value, _L("Value"), 0)									GETN_ID(nUserID++)
	GETN_LIST(region, _L("Data Region"), 0, DATA_REGION)			GETN_ID(nUserID++)
	if ( GetNBox(tr, NULL, _L("Edit Data Points"), _L("Options"), hWndParent) )
	{
		int nApplyTo = GetMultiPlotsState() ? DATA_ALL_CURVES : DATA_SELECTED_CURVE;
		UpdateData(tr.opera.nVal, tr.region.nVal, nApplyTo, tr.value.dVal);
		///Sophy 6/11/2010 ORG-25-P3 UPDATE_RESULT_DIALOG_AFTER_EDIT_POINTS
		m_gp.Refresh(TRUE);	
		LT_execute("sec -p 0.002");
		///end UPDATE_RESULT_DIALOG_AFTER_EDIT_POINTS
		return true;

	}
	return false;
}


class	RemoveRowHelper
{
public:
	RemoveRowHelper(){}
	~RemoveRowHelper(){}
	void	Init()
	{
		m_vsWorksheetNames.SetSize(0);
		m_arrIndices.SetSize(0);
		m_arrIndices.SetAsOwner(true);
	}
	int		Add(LPCSTR lpcszWorksheetName, vector<int> vnIndices)
	{
		if ( NULL == lpcszWorksheetName || strlen(lpcszWorksheetName) == 0 )
			return -1;
		
		int nIndex = m_vsWorksheetNames.Find(lpcszWorksheetName);
		if ( nIndex < 0 )
		{
			nIndex = m_vsWorksheetNames.Add(lpcszWorksheetName);
			if ( nIndex < 0 )
				return nIndex; //error
			
			vector<int>* pp;
			pp = new vector<int>;
			*pp = vnIndices;
			m_arrIndices.Add(*pp);
			return nIndex;
		}
		vector<int>& vnIndicesNew = m_arrIndices.GetAt(nIndex);
		vnIndicesNew.Append(vnIndices);
		return nIndex;
	}
	void	Handle()
	{
		int iWorksheet = 0;
		for ( iWorksheet = 0; iWorksheet < m_vsWorksheetNames.GetSize(); iWorksheet++ )
		{
			Worksheet wks(m_vsWorksheetNames[iWorksheet]);
			if ( wks )
			{
				vector<int>& vnIndices = m_arrIndices.GetAt(iWorksheet);
				vnIndices.Sort(); //sort and delete from the end to delete multiple rows
				///Sophy 4/29/2010 ORG-59 DATAPOINTS_OPERATION_SHOULD_ALLOW_UNDO
				//for ( int iRowIndex = vnIndices.GetSize() - 1; iRowIndex >= 0; iRowIndex-- )
					//wks.DeleteRow(vnIndices[iRowIndex]);
				wks.SetSelectedRange(vnIndices);
				wks.DeleteSelection(true);
				///end DATAPOINTS_OPERATION_SHOULD_ALLOW_UNDO
			}
		}
	}
private:
	vector<string>		m_vsWorksheetNames;
	Array<vector<int>&>	m_arrIndices;
};

RemoveRowHelper rrHelper;

static	bool	_update_data_one_plot(DataPlot& dp, GraphObject& gr, int nOpera, int nDataRegion, double dNewVal)
{
	if ( !dp || !gr )
		return false;
	
	vector<int> vnI1, vnI2;
	int nRegions = dp.GetDataRegions(gr, vnI1, vnI2);
	if ( DATA_OUTER_PTS == nDataRegion ) //need to update region information
	{
		ASSERT(nRegions > 0);
		vector<int> vnI1Ex(0), vnI2Ex(0);
		if ( vnI1[0] > 0 )
		{
			vnI1Ex.Add(0);
			vnI2Ex.Add(vnI1[0] - 1);
		}
		for ( int iReg = 0; iReg < nRegions - 1; iReg++ )
		{
			vnI1Ex.Add(vnI2[iReg] + 1);
			vnI2Ex.Add(vnI1[iReg + 1] - 1);
		}
		int i1, i2;
		dp.GetRange(i1, i2);
		if ( vnI2[nRegions - 1] < i2 )
		{
			vnI1Ex.Add(vnI2[nRegions-1] + 1);
			vnI2Ex.Add(i2);
		}
		vnI1 = vnI1Ex;
		vnI2 = vnI2Ex;
		nRegions = vnI1.GetSize();
	}
	
	XYRange	rngXY;
	string	strY;
	if ( dp.GetDataRange(rngXY) && rngXY.GetDatasetNames(strY) )
	{
		for ( int iReg = nRegions - 1; iReg >= 0; iReg-- )
		{
			if ( DATA_SET_VALUE == nOpera )
			{
				///Sophy 4/29/2010 ORG-59 DATAPOINTS_OPERATION_SHOULD_ALLOW_UNDO
				//Dataset ds(strY);
				//if ( ds )
				//{
					//for ( int iPt = vnI1[iReg]; iPt <= vnI2[iReg]; iPt++ )
					//{
						//ds[iPt] = dNewVal;
					//}
				//}
				vector vX, vY;
				///Sophy 6/22/2010 ORG-25-P4 PROPER_SET_DATPOINTS_VALUE_WHEN_MASKED
				//rngXY.GetData(vY, vX);
				dp.GetDataPoints(0, -1, vX, vY);
				///end PROPER_SET_DATPOINTS_VALUE_WHEN_MASKED

				//update value by a sub range
				vector vSub;
				vY.GetSubVector(vSub, vnI1[iReg], vnI2[iReg]);
				vSub = dNewVal;
				vY.SetSubVector(vSub, vnI1[iReg]);
				
				rngXY.SetData(&vY, &vX, 0, NULL, DRS_KEEP_LARGER_DEST_SIZE | DRS_FORCE_UNDO);
				///end DATAPOINTS_OPERATION_SHOULD_ALLOW_UNDO
			}
			else if ( DATA_MASK == nOpera )
			{
				DatasetObject dsObj(strY);
				if ( dsObj )
				{
					///Sophy 4/29/2010 ORG-59 DATAPOINTS_OPERATION_SHOULD_ALLOW_UNDO
					//dsObj.SetMask(vnI1[iReg], vnI2[iReg]);
					dsObj.SetMask(vnI1[iReg], vnI2[iReg], false, true);
					///end DATAPOINTS_OPERATION_SHOULD_ALLOW_UNDO
				}
			}
			else if ( DATA_DELETE_ROW == nOpera )
			{
				Column colY;
				if ( rngXY.GetYColumn(colY) )
				{
					Worksheet wks;
					colY.GetParent(wks);
					wks.GetRangeString(strY);
					
					vector<int> vnIndices;
					vnIndices.Data(vnI1[iReg], vnI2[iReg], 1);
					rrHelper.Add(strY, vnIndices);
				}
			}
			else
			{
				ASSERT(FALSE);
				return false;
			}
		}
	}
	return true;
}

bool	GraphObjCurveTool::UpdateData(int nOpera, int nDataRegion, int nApplyTo, double dNewVal)
{
	UndoBlock ub;	///Sophy 4/29/2010 ORG-59 DATAPOINTS_OPERATION_SHOULD_ALLOW_UNDO
	if ( DATA_DELETE_ROW == nOpera )
		rrHelper.Init();
	if ( DATA_CLEAR == nOpera )
	{
		dNewVal = get_missing_value();
		nOpera = DATA_SET_VALUE;
	}
	else if ( DATA_ZERO == nOpera )
	{
		dNewVal = 0;
		nOpera = DATA_SET_VALUE;
	}	

	if ( DATA_SELECTED_CURVE == nApplyTo )
	{
		DataPlot dp;
		if ( GetSelectedPlot(dp) )
			_update_data_one_plot(dp, m_go, nOpera, nDataRegion, dNewVal);
	}
	else
	{
		foreach(DataPlot dp in m_gl.DataPlots)
		{
			///Kyle 03/15/2010 IS_PLOT_FOR_ROI_GIVE_OPTION_TO_SPECIFY_THE_NAME_TO_TAG_A_DATAOBJ
			//if ( is_plot_for_ROI(dp, m_go) )
			if( is_plot_for_ROI(dp, m_go, STR_DATASETOBJ_FITCURVE) )
			///End IS_PLOT_FOR_ROI_GIVE_OPTION_TO_SPECIFY_THE_NAME_TO_TAG_A_DATAOBJ
			{
				_update_data_one_plot(dp, m_go, nOpera, nDataRegion, dNewVal);
			}
		}
	}
	if ( DATA_DELETE_ROW == nOpera )
		rrHelper.Handle();
	
	return true;
}

bool	GraphObjCurveTool::OnSetPlot(int nIndex)
{
	SetMultiPlotsState(false);
	return SetPlot(nIndex);
}
///end EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL

bool	GraphObjCurveTool::SetPlot(int nIndex)
{
	Tree trInfo;
	tree_get_binary_storage(trInfo, m_go, ATTACHED_GRAPH_OBJECTS_INFO);
	trInfo.curPlotIndex.nVal = nIndex;
	tree_put_binary_storage(trInfo, m_go, ATTACHED_GRAPH_OBJECTS_INFO);

	return true;
}

/// Iris 2/20/2010 MOVE_REPLACE_LAST_OUTPUT_TO_CONTEXT_MENU
bool	GraphObjCurveTool::GetSelectedPlot(DataPlot& dp)
{
	int nCurPlotIndex = -1;
	Tree trInfo;
	if ( tree_get_binary_storage(trInfo, m_go, ATTACHED_GRAPH_OBJECTS_INFO) && trInfo.curPlotIndex )
	{
		nCurPlotIndex = trInfo.curPlotIndex.nVal;	
	}
	else
	{
		/// Iris 2/20/2010 QUICKFIT_SHOULD_USE_SELECTED_PLOT_NOT_ACTIVE_PLOT_AS_INPUT
		//nCurPlotIndex = m_gl.DataPlots().GetIndex();
		nCurPlotIndex = m_dp? m_dp.GetIndex() : get_selected_data_plot();
		///End QUICKFIT_SHOULD_USE_SELECTED_PLOT_NOT_ACTIVE_PLOT_AS_INPUT
	}
	
	dp = m_gl.DataPlots(nCurPlotIndex);
	return dp.IsValid();
}
///End MOVE_REPLACE_LAST_OUTPUT_TO_CONTEXT_MENU

bool	GraphObjCurveTool::DoExpand()
{
	/// Iris 2/20/2010 MOVE_REPLACE_LAST_OUTPUT_TO_CONTEXT_MENU
	/*
	int nCurPlotIndex = -1;
	Tree trInfo;
	if ( tree_get_binary_storage(trInfo, m_go, ATTACHED_GRAPH_OBJECTS_INFO) && trInfo.curPlotIndex )
		nCurPlotIndex = trInfo.curPlotIndex.nVal;
	
	DataPlot dp = m_gl.DataPlots(nCurPlotIndex);
	*/
	DataPlot dp;
	GetSelectedPlot(dp);
	///End MOVE_REPLACE_LAST_OUTPUT_TO_CONTEXT_MENU
	if ( dp )
	{
		{
			ROIToolOptionAccessHelper		clHelper(ROI_OPTION_IGNORE_EVENT);

			///------ Folger 02/23/10 ROI_TOOLS_DO_EXPAND_FAILS_TO_PLACE_BUTTONS_CORRECTLY
			DoExpand(dp);
			///------ End ROI_TOOLS_DO_EXPAND_FAILS_TO_PLACE_BUTTONS_CORRECTLY
		}
		
		/// Iris 2/25/2010 FIX_EXPAND_FULL_RANGE_FIT_CURVE_UPWARD_MOVED
		//m_gp.Refresh();	///Sophy 2/11/2010 QA81-15104-P3 REFRESH_GRAPH_ON_ROI_EXPAND
		// set as true to redraw graph page after changed layer scale in DoExpand. If not redraw here, 
		// will cause draw Fit Curve based on the original layer scale.
		m_gp.Refresh(true); 
		///End FIX_EXPAND_FULL_RANGE_FIT_CURVE_UPWARD_MOVED
		///Sophy 4/29/2010 QUICKFIT_EXPAND_TO_FULL_RANGE_SHOULD_UPDATE_X_SCALE
		//graphobjtool_events(*this, m_go.GetName(), OE_RESIZE);
		graphobjtool_events(*this, m_go.GetName(), OE_RESIZE, GROBJEVENTS_FROM_EVENT_FUNCTION); //add GROBJEVENTS_FROM_EVENT_FUNCTION as quickfit do expand need to update X scale
		///end QUICKFIT_EXPAND_TO_FULL_RANGE_SHOULD_UPDATE_X_SCALE
	}

	return true;
}

/// Iris 2/25/2010 TO_FIX_ALWAYS_CHANGE_LAYER_SCALE_WHEN_EXPAND_FULL_RANGE
// before expand rect, to check and change layer axis scale if data points outside layer, and get the rect's full range.
void	GraphObjCurveTool::BeforeExpandRect(DataPlot& dp, double& dMinX, double& dMaxX, double& dMinY, double& dMaxY)
{
	vector vX, vY;
	///Sophy 6/8/2010 ORG-48-P10 PROPER_GET_DATAPLOT_POINTS_FOR_EXPAND_FULL_RANGE
	//dp.GetDataPoints(0, -1, vX, vY);
	int nR1, nC1, nR2, nC2;
	DataRange dr;
	Datasheet dsht;
	dp.GetDataRange(dr);
	dr.GetRange(0, nR1, nC1, nR2, nC2, dsht);
	dp.GetDataPoints(nR1, nR2, vX, vY);
	///end PROPER_GET_DATAPLOT_POINTS_FOR_EXPAND_FULL_RANGE
	vX.GetMinMax(dMinX, dMaxX);
	vY.GetMinMax(dMinY, dMaxY);
	
	get_min_max_inc(dMinX, dMaxX, m_gl.X.Type, 0.08);
	get_min_max_inc(dMinY, dMaxY, m_gl.Y.Type, 0.02);
	if( dMinX < m_gl.X.From )
		m_gl.X.From = dMinX;
	if( dMaxX > m_gl.X.To )
		m_gl.X.To = dMaxX;
	if( dMinY < m_gl.Y.From )
		m_gl.Y.From = dMinY;
	if( dMaxY > m_gl.Y.To )
		m_gl.Y.To = dMaxY;
	
	// get x/y min and max with marge for rect size
	vX.GetMinMax(dMinX, dMaxX);
	vY.GetMinMax(dMinY, dMaxY);
	get_min_max_inc(dMinX, dMaxX, m_gl.X.Type, 0.04);
	get_min_max_inc(dMinY, dMaxY, m_gl.Y.Type, 0.01);	
}
///End TO_FIX_ALWAYS_CHANGE_LAYER_SCALE_WHEN_EXPAND_FULL_RANGE

///------ Folger 02/23/10 ROI_TOOLS_DO_EXPAND_FAILS_TO_PLACE_BUTTONS_CORRECTLY
/// virtual
void	GraphObjCurveTool::DoExpand(DataPlot& dp)
{
	/// Iris 2/25/2010 TO_FIX_ALWAYS_CHANGE_LAYER_SCALE_WHEN_EXPAND_FULL_RANGE
	/*
	vector vX, vY;
	dp.GetDataPoints(0, -1, vX, vY);
	double dMinX, dMaxX, dMinY, dMaxY;
	vX.GetMinMax(dMinX, dMaxX);
	vY.GetMinMax(dMinY, dMaxY);
	
	double dWidth = (dMaxX - dMinX);
	double dHeight = (dMaxY - dMinY);
	get_min_max_inc(dMinX, dMaxX, m_gl.X.Type, 0.08);
	get_min_max_inc(dMinY, dMaxY, m_gl.Y.Type, 0.02);
	m_gl.X.From = dMinX;
	m_gl.X.To = dMaxX;
	m_gl.Y.From = dMinY;
	m_gl.Y.To = dMaxY;
	
	//Sophy, need the following code as to better update m_go's position, if removed, m_gl.WorldToPage will get incorrect values
	m_go.Left = dMinX;
	m_go.Width = dWidth;
	m_go.Top = dMaxY;
	m_go.Height = dHeight;
	
	int nLeft, nTop, nRight, nBottom;
	vX.GetMinMax(dMinX, dMaxX);
	vY.GetMinMax(dMinY, dMaxY);
	get_min_max_inc(dMinX, dMaxX, m_gl.X.Type, 0.04);
	get_min_max_inc(dMinY, dMaxY, m_gl.Y.Type, 0.01);
	*/
	double dMinX, dMaxX, dMinY, dMaxY;
	BeforeExpandRect(dp, dMinX, dMaxX, dMinY, dMaxY);
	
	///Sophy 4/8/2010 EXPAND_FULL_RANGE_SUPPORT_MULTIPLE_DATAPLOTS
	/*
	//Sophy, need the following code as to better update m_go's position, if removed, m_gl.WorldToPage will get incorrect values
	m_go.Left = dMinX;
	m_go.Width = (dMaxX - dMinX);
	m_go.Top = dMaxY;
	m_go.Height = (dMaxY - dMinY);		
	
	int nLeft, nTop, nRight, nBottom;
	///End TO_FIX_ALWAYS_CHANGE_LAYER_SCALE_WHEN_EXPAND_FULL_RANGE
	
	m_gl.WorldToPage(nLeft, nTop, dMinX, dMaxY);
	m_gl.WorldToPage(nRight, nBottom, dMaxX, dMinY);
	if ( is_active_graphlayer_xyexchanged() ) //need to exchange height and width
	{
		int nTemp;
		SWAP(nLeft, nRight, nTemp);
		SWAP(nTop, nBottom, nTemp);
	}

	m_go.Left = nLeft - 5;  //ten pixel margin as to include points on the edge.
	m_go.Top = nTop - 5;
	m_go.Width = abs(nRight - nLeft) + 10;
	m_go.Height = abs(nTop - nBottom) + 10;
	*/
	ExpandROI(dMinX, dMaxX, dMinY, dMaxY);
	///end EXPAND_FULL_RANGE_SUPPORT_MULTIPLE_DATAPLOTS
}
///------ End ROI_TOOLS_DO_EXPAND_FAILS_TO_PLACE_BUTTONS_CORRECTLY

///Sophy 4/8/2010 EXPAND_FULL_RANGE_SUPPORT_MULTIPLE_DATAPLOTS
void	GraphObjCurveTool::ExpandROI(double dMinX, double dMaxX, double dMinY, double dMaxY)
{
	///Sophy 5/5/2010 EXPAND_FULL_RANGE_SHOULD_DO_NOTHING_WHEN_ALL_POINTS_ARE_MISSING_VALUE
	if ( is_missing_value(dMaxY - dMinY) || is_missing_value(dMaxX - dMinX) )
	{
		error_report("Fail to expand to full range, no valid data selected.");
		return;
	}
	///end EXPAND_FULL_RANGE_SHOULD_DO_NOTHING_WHEN_ALL_POINTS_ARE_MISSING_VALUE
	m_go.Left = dMinX;
	m_go.Width = (dMaxX - dMinX);
	m_go.Top = dMaxY;
	m_go.Height = (dMaxY - dMinY);		
	
	int nLeft, nTop, nRight, nBottom;
	m_gl.WorldToPage(nLeft, nTop, dMinX, dMaxY);
	m_gl.WorldToPage(nRight, nBottom, dMaxX, dMinY);
	
	if ( is_active_graphlayer_xyexchanged() ) //need to exchange height and width
	{
		int nTemp;
		SWAP(nLeft, nRight, nTemp);
		SWAP(nTop, nBottom, nTemp);
	}

	m_go.Left = nLeft - 5;  //ten pixel margin as to include points on the edge.
	m_go.Top = nTop - 5;
	m_go.Width = abs(nRight - nLeft) + 10;
	m_go.Height = abs(nTop - nBottom) + 10;
	
}
///end EXPAND_FULL_RANGE_SUPPORT_MULTIPLE_DATAPLOTS

///Sophy 1/26/2010 ADD_GO_TO_REPORT_TABLE_MENU_IN_CONTEXT
bool	GraphObjCurveTool::DoActiveReport()
{
	Worksheet wks;
	if ( GetReportWorksheet(wks) )
	{
		wks.CheckShowActivate();
		return true;
	}
	return false;
}
///end ADD_GO_TO_REPORT_TABLE_MENU_IN_CONTEXT
///Sophy 1/19/2010 QA80-14832 ADD_SAVE_THEME_AS_IN_CONTEXT_MENU_FOR_ROI_TOOLS
bool	GraphObjCurveTool::DoSaveTheme()
{
	Tree tr;
	GetTree(tr);
	UpdateThemeTree(tr);	///Sophy 1/21/2010 QA80-14832 DISPLAY_DEFAULT_THEME_NAME_WHEN_SAVE_THEME_FOR_ROI_TOOL
	string strThemeFileName = theme_ask_save_as_filename(tr, GetWindow());
	if ( strThemeFileName.IsEmpty() )
		return false;

	BOOL bSaved = theme_save_settings(tr, strThemeFileName);
	if( !bSaved )
		popup_errmsg_save_readonly_file(strThemeFileName, GetWindow() );
	
	///------ Folger 02/01/10 CURRENT_THEME_NAME_SHOULD_SHOW_WHEN_SAVE_THEME_AS_IN_ROI_TOOLS
	GetGUITree(tr);
	tr.SetAttribute(STR_THEME_FILE_ATTRIB, strThemeFileName);
	SetGUITree(tr);
	///------ End CURRENT_THEME_NAME_SHOULD_SHOW_WHEN_SAVE_THEME_AS_IN_ROI_TOOLS
	
	return bSaved;
}
///end ADD_SAVE_THEME_AS_IN_CONTEXT_MENU_FOR_ROI_TOOLS

///Sophy 1/19/2010 QA80-14832 SHOW_TOOLNAME_FOR_ROI_TOOLS
bool	GraphObjCurveTool::CheckUpdateToolName()
{
	Tree trGUI;
	GetGUITree(trGUI);
	TreeNode trToolName = GetToolNameNode(trGUI);
	if ( trToolName )
	{
		m_vnObjIDs.Add(GOT_OBJ_NAME);
		m_vsObjNames.Add("ToolName");
		
		int nShow = 0;
		trToolName.GetAttribute(STR_ATTRIB_DYNACONTROL_USE_CHECK, nShow);
		
		if ( nShow == 1 )
		{
			if ( GetAttachment(m_goToolName, GOT_OBJ_NAME) < 0 )
			{
				CreateAttachment(m_goToolName, GOT_OBJ_NAME, CTP_INNER_LEFT_TOP, GROT_TEXT, trToolName.strVal);
				SetLabelTransparent(m_goToolName);
				set_go_selectable(m_goToolName, false);
			}
			else
			{
				m_goToolName.Text = trToolName.strVal;
				connect_justify(m_go, m_goToolName, CTP_INNER_LEFT_TOP, &m_gapCtrl); //once the content changed, may need to justify again
				m_goToolName.Show(true);
			}
		}
		else
		{
			if ( GetAttachment(m_goToolName, GOT_OBJ_NAME) == 0 )
				m_goToolName.Show(false); //hide it.
		}
		
	}
	return true;
}
///end SHOW_TOOLNAME_FOR_ROI_TOOLS
//---- CPY 2/2/10 CONTEXT_MENU_POPUP_POSITION_MAKE_CONSISTENT
// this function seems no longer used, should be cleaned up
/*
bool	GraphObjCurveTool::DoShowPlots()
{
	int nCurPlotIndex = -1;
	Tree trInfo;
	if ( tree_get_binary_storage(trInfo, m_go, ATTACHED_GRAPH_OBJECTS_INFO) && trInfo.curPlotIndex )
	{
		nCurPlotIndex = trInfo.curPlotIndex.nVal;
	}
	else
		nCurPlotIndex = m_gl.DataPlots().GetIndex();
	
	
	Menu pm;
	string strLabel;
	vector<int> vI1;
	vector<int> vI2;
	DataPlot dpActive = m_gl.DataPlots(nCurPlotIndex);
	if ( dpActive && dpActive.GetDataRegions(m_go, vI1, vI2) <= 0 )
	{
		nCurPlotIndex = -1;
	}
	XYRange xySrc;
	Column colY;
	foreach(DataPlot dp in m_gl.DataPlots)
	{
		if ( (dp.GetDataRegions(m_go, vI1, vI2) > 0) && dp.GetDataRange(xySrc) && xySrc.GetYColumn(colY) && !is_dataobj_tagged(colY, STR_DATASETOBJ_FITCURVE) ) 
		{
			if ( nCurPlotIndex < 0 ) //if previously active plot is not in region, should set another one as active
				nCurPlotIndex = dp.GetIndex();
			
			string strName;
			dp.GetRangeString(strName, NTYPE_SHORT_NAME_ONLY | NTYPE_BOOKSHEET_XY_RANGE | NTYPE_ADD_ROW_RANGE);
			strLabel.Format("Plot(%d)%s\t%s", dp.GetIndex() + 1, (nCurPlotIndex == dp.GetIndex() ? "*" : ""), strName);
			pm.Add(strLabel, dp.GetIndex() + 1);
		}
	}
	
	int nCmdID = 0;
	POINT pt;
	int XAdj = m_goPlots.Width * 0.1, YAdj = m_goPlots.Height * 0.07;
	GetCursorPos(&pt);
	pm.TrackPopupMenu(TPM_LEFTBUTTON | TPM_LEFTALIGN  , pt.x + XAdj, pt.y - YAdj, GetWindow(), &nCmdID);
	if ( nCmdID != 0 )
	{
		trInfo.curPlotIndex.nVal = nCmdID - 1;
		tree_put_binary_storage(trInfo, m_go, ATTACHED_GRAPH_OBJECTS_INFO);
		if ( nCmdID - 1 != nCurPlotIndex )
			OnMove(); //as to update result.
	}
	return true;
}
*/
//----- end CONTEXT_MENU_POPUP_POSITION_MAKE_CONSISTENT


bool	GraphObjCurveTool::UpdateInnerAttachments()
{
	CheckUpdateToolName();
	///Sophy 2/11/2010 QA81-15107 SUPPORT_EXTEND_POSITION_FOR_GRAPHOBJECT_CONNECT
#ifndef	__EXTEND_POSITION_FOR_GROBJ_CONNECT__
	return connect_justify(m_go, m_goClose, CTP_INNER_RIGHT_TOP, &m_gapCtrl);
#else
	///Sophy 3/1/2010 OC_WORKAROUND_FOR_CONNECTED_OBJ_WRONG_POSITION_ON_LAYER_RESIZE
#define	__CTP_POSITION_NOT_FIXED__
#ifdef	__CTP_POSITION_NOT_FIXED__
	connect_justify(m_go, m_goClose, CTP_INNER_RIGHT_TOP, &m_gapCtrl);
	connect_justify(m_go, m_goContext, CTP_RIGHT_TOP, &m_gapCtrl);
#else
	//do nothing
#endif	//__CTP_POSITION_NOT_FIXED__
	return true;
	///end OC_WORKAROUND_FOR_CONNECTED_OBJ_WRONG_POSITION_ON_LAYER_RESIZE
	return true;
#endif	//__EXTEND_POSITION_FOR_GROBJ_CONNECT__
}
///end CLEAN_CODE_FOR_ROI_TOOLS
///Sophy 8/21/2009 QA80-14175 CREATE_ALL_NODES_IN_ONE_TREE_TO_GET_RID_OF_OPTIONS_BRANCH
int	GraphObjCurveTool::UpdateMainRect(const TreeNode& trGUI)
{
	if ( !m_go )
		return 1;
	
	
	Tree trFormat;
	trFormat = m_go.GetFormat(FPB_ALL, FOB_ALL, true, true);
	///Sophy 1/18/2010 CLEAN_CODE_SUPPORT_FLEXIBLE_COLOR_SETTING_ACCESS
	//trFormat.Root.Fill.Color.nVal = trGUI.rectcolor.nVal;
	TreeNode trColor = GetFillColorNode(trGUI);
	if ( trColor )
		trFormat.Root.Fill.Color.nVal = trColor.nVal;
	///end CLEAN_CODE_SUPPORT_FLEXIBLE_COLOR_SETTING_ACCESS
	if ( m_go.ApplyFormat(trFormat, true, true) )
	{
		MakePrintable(m_go);	///Sophy 8/26/2009 QA80-14169 MAKE_GRAPHOBJECT_FOR_PROGRAMMING_CONTROL_PRINTABLE when doEdit and if not set again, will not be printable
		return 0;
	}
	return 1;
}
///end CREATE_ALL_NODES_IN_ONE_TREE_TO_GET_RID_OF_OPTIONS_BRANCH
bool GraphObjCurveTool::SetGUITree(const TreeNode& trGUI)
{
	Tree tr;
	GetTree(tr);
	tr.GUI.Replace(trGUI.Clone(), true, true);
	return SetTree(tr);
}
bool GraphObjCurveTool::GetGUITree(Tree& trGUI)
{
	Tree tr;
	if ( GetTree(tr) )
	{
		trGUI = tr.GUI;
		///Sophy 11/26/2009 EVT_HANDLER_IN_TREENODE_INVALID_WHEN_RESTART_ORIGIN
		UpdateGUITree(trGUI);
		///end EVT_HANDLER_IN_TREENODE_INVALID_WHEN_RESTART_ORIGIN
		return trGUI.IsValid();
	}
	return false;
}

///Sophy 11/26/2009 EVT_HANDLER_IN_TREENODE_INVALID_WHEN_RESTART_ORIGIN
typedef int(*PFN_XF_MAKE_TREE)(TreeNode& tr, LPCSTR lpcszVarName);
void	GraphObjCurveTool::UpdateGUITree(TreeNode& trGUI)
{
	int* pnXFEvtHandlerState = GetXFEventHandlersState();
	if ( pnXFEvtHandlerState != NULL && 0 == *pnXFEvtHandlerState )
	{
		///------ Foler 04/12/10 QA81-15288 QUICKFIT_BACKWARD_COMPATIBILITY_FOR_81SR2
		//string strXFName = GetXFName();
		//string strFuncName;
		//strFuncName.Format("%s_make_tree", strXFName);
		//Tree tr;
		
		//PFN_XF_MAKE_TREE pfn = Project.FindCompiledFunction(strFuncName);
		//if ( pfn )
		//{
			//pfn(tr, "trGUI");
		Tree	tr;
		if ( MakeTree(tr) )
		{
		///------ End QUICKFIT_BACKWARD_COMPATIBILITY_FOR_81SR2
			///Sophy 1/28/2010 FAIL_TO_APPLY_THEME_SETTINGS_DUE_TO_EVT_HANGLER_UPDATE_CODE here should only update "Handle" attribute
			//tree_copy_values(trGUI, tr);
			//trGUI.Replace(tr);
			octree_copy_atts_by_id(&tr, &trGUI, STR_ATTRIB_HANDLER);
			octree_copy_atts_by_id(&tr, &trGUI, STR_GETN_HANDLE);	///Sophy 6/10/2010 ORG-48-P14 BETTER_EVENT_HANDLE_FOR_PREFERENCE_IN_ROI_TOOLS
			///end FAIL_TO_APPLY_THEME_SETTINGS_DUE_TO_EVT_HANGLER_UPDATE_CODE
			///------ Folger 09/14/2010 PICK_PEAK_GADGET_FAILED_TO_WORK_AFTER_RELOAD_PROJECT
			octree_copy_atts_by_id(&tr, &trGUI, STR_ATTRIB_HANDLER_RC);
			///------ End PICK_PEAK_GADGET_FAILED_TO_WORK_AFTER_RELOAD_PROJECT
			SetGUITree(trGUI); //should save GUI tree after handler updated for later use.
			*pnXFEvtHandlerState = 1;
		}
	}
}
///end EVT_HANDLER_IN_TREENODE_INVALID_WHEN_RESTART_ORIGIN

///------ Foler 04/12/10 QA81-15288 QUICKFIT_BACKWARD_COMPATIBILITY_FOR_81SR2
BOOL	GraphObjCurveTool::RemakeGUITree()
{
	Tree	tr;
	if ( !MakeTree(tr) )
		return FALSE;

	Tree	trGUI;
	GetGUITree(trGUI);
	
	octree_copy_values_by_id(&trGUI, &tr);
	octree_copy_atts_by_id(&trGUI, &tr, STR_SHOW_ATTRIB);

	octree_node_copy_attribute(&trGUI, &tr, STR_THEME_FILE_ATTRIB);
	
	SetGUITree(tr);	
	return SetVersion();
}

/// virtual
BOOL	GraphObjCurveTool::MakeTree(TreeNode& tr)
{
	string strXFName = GetXFName();
	string strFuncName;
	strFuncName.Format("%s_make_tree", strXFName);
	
	PFN_XF_MAKE_TREE pfn = Project.FindCompiledFunction(strFuncName);
	if ( pfn )
	{
		pfn(tr, "trGUI");
		return TRUE;
	}
	
	return FALSE;
}
///------ End QUICKFIT_BACKWARD_COMPATIBILITY_FOR_81SR2

bool GraphObjCurveTool::SetResultsTree(const TreeNode& trResults)
{
	Tree tr;
	GetTree(tr);
	if(trResults)
	{
		///Sophy 1/23/2010 MAKE_QUICK_CURVE_STATS_AS_STANDARD_ROI_TOOL
		//as to Max's suggestion, all ROI tools output to worksheet should not rename column Short Name
		trResults.SetAttribute(STR_TR2WKS_NO_RENAME_SNAME_ATTRIB, TRUE);
		tree_set_attribute_to_all_nodes(trResults, STR_TR2WKS_NO_RENAME_SNAME_ATTRIB, "1");	///Sophy 7/14/2010 ORG-558 ALL_ROI_TOOLS_SHOULD_NOT_RENAME_OUTPUT_COLUMN_SHORTNAME
		///end MAKE_QUICK_CURVE_STATS_AS_STANDARD_ROI_TOOL
		///Sophy 6/12/2009 IMPROVE_RISETIME_TOOL_FOR_OSCILLOSCOPE_SIGNAL_PROCESSING
#ifdef	IMPROVE_RISETIME_TOOL
		tr.Results.Replace(trResults.Clone(), true, true); //need to remember some attribute
#else	//keep old logic
		tr.Results.Replace(trResults.Clone(), true, true, true);
#endif	//IMPROVE_RISETIME_TOOL
		///end IMPROVE_RISETIME_TOOL_FOR_OSCILLOSCOPE_SIGNAL_PROCESSING
	}
	else
		tr.Results.Remove();
	return SetTree(tr);
}
//virtual
bool GraphObjCurveTool::GetResultsTree(TreeNode& trResults)
{
	Tree tr;
	if ( GetTree(tr) && tr.Results)
	{
		trResults = tr.Results;
	}
	
	return trResults.IsValid();	
}

///Sandy add 2009-2-24 get result tree by clone sub-tree of gui
bool GraphObjCurveTool::GetResultsTree(TreeNode& trResults, LPCSTR lpcszTagName)
{
	Tree tr;
	if ( GetTree(tr) )
	{
		if ( !tr.Results )
		{
			ASSERT(tr.GUI);
			
			TreeNode trOutputQuantites = tr.GUI.GetNode(lpcszTagName);
			ASSERT(trOutputQuantites);
			//tr.results.DataID = tr.GUI.quantites.DataID + 1;
			tr.Results.Replace(trOutputQuantites.Clone(), true, true, true);
			tree_remove_attribute(tr.results, STR_ID_ATTRIB); // GETN_CHECK etc things no longer needed and better clean it
			tree_remove_attribute(tr.results, STR_LABEL_ATTRIB); // to avoid double storage, they will be transfered over later anyway
			SetTree(tr);
		}
		trResults = tr.Results;
	}
	
	return trResults.IsValid();
}

void GraphObjCurveTool::ConnectToTempPreviewDataAndGraph()
{
	if(!m_wks && !m_strPreviewDataWksName.IsEmpty())
		m_wks.Attach(m_strPreviewDataWksName);
	
	if(m_strPreviewGraphName.IsEmpty())
		m_strPreviewGraphName = m_strGraphTemplate;
	if(!m_glPreview && !m_strPreviewGraphName.IsEmpty())
	{
		GraphPage gp(m_strPreviewGraphName);
		if(gp)
			m_glPreview = gp.Layers(0);
	}
}

BOOL GraphObjCurveTool::OnDestroy()
{
	if(GraphObjTool::OnDestroy())
	{
		if(GetTotalNumTools() < 1)
		{
			ConnectToTempPreviewDataAndGraph();
			if(m_wks)
				m_wks.Destroy();
			if(m_glPreview)
				m_glPreview.Destroy();
		}
	}
	return true;
}

///Sandy 2009-2-25 add CENTRALIZE_TO_BASE_CLASS_GROBJ_UTILS
void 	GraphObjCurveTool::OutputResultTree(bool bToScript, bool bToResLog, bool bAppendWks, string strWksPageName, DWORD dwCtrl)
{
	TreeNode trResults;
	if(!GetResultsTree(trResults))
	{
		error_report("Invalid Result Tree in GraphObjCurveTool::OutputResultTree()");
		return;
	}
	
	if(bAppendWks)
	{
		///------ Folger 01/21/09 QA81-14995 GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
		//WorksheetPage wp(strWksPageName);
		//Worksheet resWks;
		//if(!wp)
		//{
			//wp.Create("Origin", CREATE_NACTIVE);
			//resWks = wp.Layers(0);
			//resWks.SetSize(-1, 0);
			//wp.Rename(strWksPageName);
		//}
		//else
			//resWks = wp.Layers(0);
		//
		//out_tree_to_wks(trResults, resWks);
		///Sophy 1/26/2010 ADD_GO_TO_REPORT_TABLE_MENU_IN_CONTEXT
		//out_tree_to_wks(trResults, strWksPageName);
		out_tree_to_wks(trResults, strWksPageName, CREATE_HIDDEN | CREATE_LOAD_1ST_LAYER_ONLY);
		///end ADD_GO_TO_REPORT_TABLE_MENU_IN_CONTEXT
		///------ End GADGET_TOOLS_SHOULD_USE_SAME_WORKSHEET_OUTPUT_NOTATION
	}
	if(bToScript || bToResLog)
	{
		Tree trTemp;
		trTemp = trResults;
		///Sophy 12/17/2009 QA80-14598-P4 RISE_TIME_TOOL_NEED_CREATE_LONGNAME_IN_RESULT_COLUMN
		if ( dwCtrl & OUTTREE_USE_TAGNAME_IN_SCRIPT_WIN )
			tree_remove_attribute(trTemp, STR_LABEL_ATTRIB); 
		///end RISE_TIME_TOOL_NEED_CREATE_LONGNAME_IN_RESULT_COLUMN
		trTemp.Show = 1;
		string strOut;
		vector<int> vnTableDisplayFormat = { DISPLAY_CENTER, DISPLAY_RIGHT, DISPLAY_RIGHT};

		///Sophy 8/19/2009 DUMP_RESULT_WITH_DOUBLE_USE_GLOBAL_DECIMAL_DIGIT_SETTINGS
		//tree_to_str(trTemp, strOut, vnTableDisplayFormat, TREE2STR_SKIP_HIDDEN | TREE2STR_SIMPLE_TYPE_ONLY | dwCtrl);
		string strDoubleFormat = "*";
		///Sophy 1/27/2010 TREE_TO_STR_SUPPORT_SPECIFY_SEPARATOR_FOR_NAME_AND_VALUE
		//tree_to_str(trTemp, strOut, vnTableDisplayFormat, TREE2STR_SKIP_HIDDEN | TREE2STR_SIMPLE_TYPE_ONLY | dwCtrl, strDoubleFormat);
		dwCtrl |= TREE2STR_SKIP_HIDDEN | TREE2STR_SIMPLE_TYPE_ONLY | TREE2STR_USE_TAB_AS_SEPARATOR;
		tree_to_str(trTemp, strOut, vnTableDisplayFormat, dwCtrl, strDoubleFormat);
		///end TREE_TO_STR_SUPPORT_SPECIFY_SEPARATOR_FOR_NAME_AND_VALUE
		///end DUMP_RESULT_WITH_DOUBLE_USE_GLOBAL_DECIMAL_DIGIT_SETTINGS
		if(bToScript)
		{
			LT_execute("type -a");
			///Sophy 2/1/2010 SHOW_DATA_TIME_STAMP_WHEN_OUTPUT_TO_SCRIPT_WINDOW
			Tree tr;
			GetTree(tr);
			if ( tr.OpDateTime )
			{
				out_str(tr.OpDateTime.strVal);
			}
			///end SHOW_DATA_TIME_STAMP_WHEN_OUTPUT_TO_SCRIPT_WINDOW
			out_str(strOut);
		}
		if(bToResLog)
		{
			if(m_gp) // should really have this
			{
				Project.OutStringToResultsLog("", false, m_gp.GetName());
			}
			strOut.WriteLine(WRITE_OUTPUT_LOG);
		}
	}	
}


void GraphObjCurveTool::GetRectCoordinate(double& dLeft, double& dRight, double& dTop, double& dBottom)
{
	///Sophy 2/4/2010 PROPERLY_UPDATE_GROBJ_POSITION_ACCORDING_TO_LAYER_SCALE
	//FRECT frect;
	//m_go.GetTempBoundingBox(&frect);
	//double x1 = m_gl.X.From;
	//double x2 = m_gl.X.To;
	//double xx1 = x1 + frect.left * (x2-x1);
	//double xx2 = x1 + frect.right * (x2-x1);
	//double y1 = m_gl.Y.To;
	//double y2 = m_gl.Y.From;
	//double yy1 = y1 + frect.bottom * (y2-y1);
	//double yy2 = y1 + frect.top * (y2-y1);
	double xx1, xx2, yy1, yy2;
	int nLeft, nTop, nRight, nBottom;
	nLeft = m_go.Left;
	nRight = m_go.Left + m_go.Width;
	nTop = m_go.Top;
	nBottom = m_go.Top + m_go.Height;
	m_gl.PageToWorld(xx1, yy1, nLeft, nBottom);
	m_gl.PageToWorld(xx2, yy2, nRight, nTop);
	///end PROPERLY_UPDATE_GROBJ_POSITION_ACCORDING_TO_LAYER_SCALE
	if(dLeft != NULL)
		dLeft = xx1;
	
	if(dRight != NULL)
		dRight = xx2;
	
	if(dTop != NULL)
		dTop =yy2;
	
	if(dBottom != NULL)
		dBottom = yy1;
}


//---- end CENTRALIZE_ADD_RECT_FOR_ALL_TOOLS

///Sophy 1/18/2010 CLEAN_CODE_SUPPORT_FLEXIBLE_COLOR_SETTING_ACCESS
//virtual
TreeNode	GraphObjCurveTool::GetFillColorNode(const TreeNode& trGUI)
{
	TreeNode trColor;
	if ( trGUI )
		trColor = trGUI.rectcolor;
	ASSERT(trColor);
	return trColor;
}
///end CLEAN_CODE_SUPPORT_FLEXIBLE_COLOR_SETTING_ACCESS

///Sophy 1/19/2010 QA80-14832 SHOW_TOOLNAME_FOR_ROI_TOOLS
//virtual
TreeNode	GraphObjCurveTool::GetToolNameNode(const TreeNode& trGUI)
{
	TreeNode trToolName;
	if ( trGUI )
		trToolName = trGUI.toolname;
	ASSERT(trToolName);
	return trToolName;
}
///end SHOW_TOOLNAME_FOR_ROI_TOOLS
///---Sim 01-08-2010 QA81-14930 CLEAN_GRAPH_OBJ_TOOLS
//virtual
bool GraphObjCurveTool::SaveClassInfo(TreeNode& tr)
{
	//tr.attObjNames.strVals = m_attObjNames;
	//tree_put_binary_storage( tr, m_go, GRAPH_TOOL_CLASS_INFO );	
	
	return true;
}
//virtual
bool GraphObjCurveTool::LoadClassInfo(const TreeNode& tr)
{
	//tree_get_binary_storage( tr, m_go, GRAPH_TOOL_CLASS_INFO );
	//if(tr.attObjNames)
	//{
		//vector<string> vsTemp;
		//vsTemp = tr.attObjNames.strVals;
		//for(int ii = 0; ii < vsTemp.GetSize() && ii < CTP_SIZE; ii ++)
			//m_attObjNames[ii] = vsTemp[ii];
		//
		//return true;
	//}
	
	return true;
}
///---END QA81-14930 CLEAN_GRAPH_OBJ_TOOLS

/// Iris 1/27/2010 ADD_LEFTX_RIGHTX_IN_ROI_TAB	
//virtual
bool GraphObjCurveTool::CheckSetMainObjectXPosition(double& x0, double& x1)
{
	/// Iris 2/10/2010 QA81-15099 FIX_BAD_ROI_INIT_POS_WHEN_LAYER_FROM_LARGE_THAN_TO
	/*
	if( x0 > x1 )
	{
		double tmp;
		tmp = x0;
		x0 = x1;
		x1 = tmp;
	}
	
	if( x0 < m_gl.X.From )
		x0 = m_gl.X.From;
	
	if( x1 > m_gl.X.To )
		x1 = m_gl.X.To;
	*/
	#pragma xor(push, FALSE)
	BOOL	bDescending = m_gl.X.From > m_gl.X.To;

	if( bDescending ^ (x0 > x1) )
	{
		double tmp;
		tmp = x0;
		x0 = x1;
		x1 = tmp;
	}
	
	if( bDescending ^ (x0 < m_gl.X.From) )
		x0 = m_gl.X.From;
	
	if( bDescending ^ (x1 > m_gl.X.To) )
		x1 = m_gl.X.To;
	///End FIX_BAD_ROI_INIT_POS_WHEN_LAYER_FROM_LARGE_THAN_TO

	int nType;
	m_go.GetObjectType(&nType);
	if( GROT_RECT == nType ) // the current Main graph object type all are rect, if not rect, need override this function.
	{
		//---- Iris 1/28/2010 this way not exact to set position, for example, set 2 as left, but in fact it is 2.0031
		//goMain.X = x0 + (x1-x0)/2.0;
		//goMain.DX = x1 - x0;		
		Tree tr;
		tr.Root.Dimension.Units.nVal = UNITS_SCALE;
		tr.Root.Dimension.Attachment.nVal = 2;
		
		if(0 != m_go.UpdateThemeIDs(tr.Root) )
		{
			ASSERT(false); return false;
		}
		
		if( !m_go.ApplyFormat(tr, true, true) )
		{
			ASSERT(false); return false;
		}				
		
		vector vv(4);
		vv[0] = x0; vv[1] = x1; vv[2] = x1; vv[3] = x0;
		
		tr.Reset();
		tr.Root.Data.X.dVals = vv;
		
		if(0 != m_go.UpdateThemeIDs(tr.Root) )
		{
			ASSERT(false); return false;
		}				
			
		bool bRet = m_go.ApplyFormat(tr, true, true);						
		
		if( bRet )
		{
			graphobjtool_events(*this, m_go.GetName(), OE_RESIZE);
		}
		return bRet;
		//---- 
	}
	ASSERT(false);
	return false;	
}
///End ADD_LEFTX_RIGHTX_IN_ROI_TAB

///Kyle 09/08/2010 ORG-998-P6 SHOW_BASELINE_INSIDE_THE_RECTANGLE_ONLY
// virtual
bool GraphObjCurveTool::GetMainObjectXPosition(double& x0, double& x1)
{
	if( !m_go )
		return false;

	int nType;
	m_go.GetObjectType(&nType);
	if( GROT_RECT != nType )
		return false;

	Tree tr;
	tr = m_go.GetFormat(FPB_DATA, FOB_ALL, true, true);
	if( !(tr.Root && tr.Root.Data) )
		return false;

	vector vx;
	vx = tr.Root.Data.X.dVals;
	vx.GetMinMax(x0, x1);

	return true;
}
///End SHOW_BASELINE_INSIDE_THE_RECTANGLE_ONLY

///------ Folger 02/04/10 SUPPORT_LOAD_THEME_IN_ROI_TOOLS_CONTEXT_MENU
void	GraphObjCurveTool::AddThemes(Menu& pm)
{
	vector<string>		vsThemes;
	vector<string>		vsFiles;
	int					nCount = okutil_theme_get_class_settings(GetXFName(), &vsFiles, &vsThemes, THTYPE_ANALYSIS, TRUE, TRUE);
	if ( 0 == nCount )
		return;
	
	int					nSel = vsThemes.Find(GetCurrentThemeName());
	vector<int>			vnCategories;
	okutil_prepare_theme_display_names(&vsThemes, &vnCategories);
	int				nLastCategories = vnCategories[0];
	
	Menu				subMenu;
	for ( int ii=0; ii<nCount; ++ii )
	{
		int nFlag = nSel == ii ? MF_CHECKED : MF_UNCHECKED;
		
		if ( nLastCategories != vnCategories[ii] )
		{
			subMenu.Add(NULL, 0, MF_SEPARATOR);
			nLastCategories = vnCategories[ii];
		}
		subMenu.Add(vsThemes[ii], GOT_BTN_THEMES | (ii + 1), nFlag);
	}
	
	pm.AddPopup(STR_DO_THEMES, subMenu, GOT_BTN_THEMES);
}

/// virtual
bool	GraphObjCurveTool::UpdateROIGUI()
{
	Tree	trGUI;
	GetGUITree(trGUI);

	UpdateMainRect(trGUI);
	CheckUpdateToolName();
	UpdateAttachments();	///Sophy 10/15/2010 ORG-1263-P1 UPDATE_INDICATOR_SETTINGS_FOR_RISETIME_TOOL
	OnMove();

	return true;
}

/// virtual
void	GraphObjCurveTool::UpdateGUIOnThemeChange(TreeNode& trGUI)
{
	m_gp.Refresh();
}
///------ End SUPPORT_LOAD_THEME_IN_ROI_TOOLS_CONTEXT_MENU

void graphobjtool_events(GraphObjTool& iTool, LPCSTR lpcszMainObjName, int nEvent, int nMsg)
{
	//if ( nMsg != 0 || OE_RESIZE == nEvent )
		//iTool.CheckAttachObjs();
	iTool.Init(lpcszMainObjName);
	iTool.OnEvent(nEvent, nMsg);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////Dialog Implementation Related//////////////////////////////////////////
///Sophy 3/8/2010 EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
#define	STR_DLG_NAME	_L("Gadget Dialog")

GadgetDlg::GadgetDlg() : ResizeDialog(IDD_GADGET_DLG, "ODlg8")
{
}

GadgetDlg::~GadgetDlg()
{
}

BOOL	GadgetDlg::Create(HWND hWndParent)
{
	InitMsgMap();
	
	DWORD dwOptions = 0;
	BOOL bRet = ResizeDialog::Create(hWndParent, dwOptions);
	Visible = true;
	return bRet;
}

BOOL	GadgetDlg::OnInitDialog()
{
	ResizeDialog::OnInitDialog(IDC_BOTTOM_TAB, STR_DLG_NAME);
	m_TableOne.Init(IDC_VSFLEXGRID_1, *this, STR_DLG_NAME);
	m_TableTwo.Init(IDC_VSFLEXGRID_2, *this, STR_DLG_NAME);
	
	m_BottomTab = GetItem(IDC_BOTTOM_TAB);
	m_BottomTab.InsertItem(TAB_INNER_POINTS, _L("Inner Points"));
	m_BottomTab.InsertItem(TAB_OUTER_POINTS, _L("Outer Points"));
	m_BottomTab.SetCurSel(0);
	OnTabChange(m_BottomTab);
	Text = STR_DLG_NAME;
	
	InitButtons();
	ArrangeControls();
	UpdateDlgData();
	return TRUE;
}

BOOL	GadgetDlg::OnReady()
{
	SetInitReady();
	return TRUE;
}

BOOL	GadgetDlg::OnDlgResize(int nType, int cx, int cy)
{
	if ( !IsInitReady() )
		return FALSE;
	
	MoveControlsHelper _temp(this);
	Control cc;
	RECT rr;
	GetControlClientRect(IDC_BOTTOM_TAB, rr, &cc);
	rr.bottom = cy;
	rr.right = cx;
	MoveControl(cc, rr);
	
	GetControlClientRect(IDC_BOTTOM_TAB, rr, &cc);
	m_BottomTab.AdjustRect(FALSE, &rr);
	MoveControl(GetItem(IDC_VSFLEXGRID_1), rr);
	MoveControl(GetItem(IDC_VSFLEXGRID_2), rr);
	return TRUE;
}

BOOL	GadgetDlg::OnRestoreSize(DWORD dwSizeInfo)
{
	return FALSE;
}

BOOL	GadgetDlg::OnDestroy()
{
	ResizeDialog::OnDestroy();
	return TRUE;
}

BOOL	GadgetDlg::OnHelp(int &nHelpID, int nIdCtrlFocus)
{
	return TRUE;
}

BOOL	GadgetDlg::OnOK()
{
	return FALSE; //return FALSE to prevent from closing
}

BOOL	GadgetDlg::OnCancel()
{
	string	strCmd;
	strCmd.Format("label -rc %s", m_strMainObjName);
	LT_execute(strCmd);
	Visible = false; //hide it
	return FALSE; //return FALSE to prevent calling OnDestroy
}


BOOL	GadgetDlg::OnTabChange(Control ctrl)
{
	const int nCurSel = m_BottomTab.GetCurSel();
	m_TableOne.SetVisible(TAB_INNER_POINTS == nCurSel);
	m_TableTwo.SetVisible(TAB_OUTER_POINTS == nCurSel);
	return TRUE;
}

BOOL	GadgetDlg::OnBeforeMouseDownTable(Control cntrl, short nButton, short nShift, float X, float Y, BOOL* pCancel)
{
	if ( MK_RBUTTON == nButton )
	{
		Control ctrl;
		const int nCurSel = m_BottomTab.GetCurSel();
		if ( TAB_INNER_POINTS == nCurSel )
		{
			m_TableOne.OnBeforeMouseDown(ctrl, nButton, nShift, X, Y, pCancel);
		}
		else if ( TAB_OUTER_POINTS == nCurSel )
		{
			m_TableTwo.OnBeforeMouseDown(ctrl, nButton, nShift, X, Y, pCancel);
		}
		return TRUE;
	}
	if ( pCancel && !m_TableOne.IsMouseOnHeader() && !m_TableTwo.IsMouseOnHeader() )
		*pCancel = TRUE; //force NOT editable.
	return FALSE;
}

BOOL	GadgetDlg::OnActiveLayerChange()
{
	BOOL bVisible = StartGadget();
	Visible = bVisible;
	return bVisible;
}

BOOL	GadgetDlg::OnActivateReport(Control ctrl)
{
	return FALSE; //to do
}

BOOL	GadgetDlg::OnPreferences(Control ctrl)
{
	return FALSE; //to do
}

BOOL	GadgetDlg::OnResultSheetChange(Control ctrl)
{
	string strText = ctrl.Text;
	return UpdateReportSheetName(strText);	///Sophy 6/25/2010 ORG-25-P5 UPDATE_REPORT_SHEET_NAME_FROM_GADGETTOOL_DLG
}

BOOL	GadgetDlg::CheckInitTool()
{
	m_gl = Project.ActiveLayer();
	if ( !m_gl )
		return FALSE;
	if ( !get_ROI_main_obj_name(m_gl, GetToolType(), m_strMainObjName) )
		return FALSE;
	return TRUE;
}

BOOL	GadgetDlg::ArrangeControls()
{
	//temp testing code begin
	SetControlGap(3);
	vector<uint> vnGroupBtnIDs = {
		IDC_BTN_PREPERENCES,
		IDC_BTN_ACTIVATE_REPORT
	};
	const int nControlGap = GetControlGap();
	int nBottom = ArrangeControlsLeftRight(vnGroupBtnIDs, nControlGap, nControlGap, nControlGap);
	Button btnFirst;
	RECT rFirstBtn;
	GetControlClientRect(vnGroupBtnIDs[0], rFirstBtn, &btnFirst);
	
	vector<uint> vnControlIDs = {
		IDC_REPORT_LABEL,
		IDC_EDIT_REPORT_SHEET,
		IDC_OUTPUT_RESULT
	};
	nBottom = ArrangeControlsLeftRight(vnControlIDs, nControlGap, nBottom + 2 * nControlGap, nControlGap);
	
	Control cFrame = GetItem(IDC_FRAME);
	MoveControl(cFrame, rFirstBtn);
	cFrame.Visible = false;
	
	Control tab;
	RECT rTab;
	GetControlClientRect(IDC_BOTTOM_TAB, rTab, &tab);
	rTab.top = nBottom + nControlGap;
	rTab.left = nControlGap;
	MoveControl(tab, rTab);
	//temp testing code end
	return FALSE; //to do
}

BOOL	GadgetDlg::InitButtons()
{
	vector<uint> vnBtnsToHide = {
		IDC_BTN_ACTIVATE_REPORT,
		IDC_BUTTON1,
		IDC_BUTTON2,
		IDC_BUTTON3, 
		IDC_BUTTON4, 
		IDC_BUTTON5, 
		IDC_BUTTON6, 
		IDC_BUTTON7, 
		IDC_BUTTON8
	}
	for ( int iBtn = 0; iBtn < vnBtnsToHide.GetSize(); iBtn++ )
	{
		Button btn = GetItem(vnBtnsToHide[iBtn]);
		if ( btn )
			btn.Visible = false;
	}
	
	vector<uint> vnBtns = {
		IDC_BTN_PREPERENCES,
		IDC_BTN_ACTIVATE_REPORT,
		IDC_OUTPUT_RESULT
	};
	
	vector<string> vsBtnTips(vnBtns.GetSize());
	
	vsBtnTips[0] = _L("Preferences");
	vsBtnTips[1] = _L("Go");
	vsBtnTips[2] = _L("Output Report");
	
	vector<int> vnBitmaps = {
		IDB_PF_ADV,
		IDB_ACTIVATE_WKS,
		IDB_DUMP_DATA_INTO_WKS
	};
	for ( iBtn = 0; iBtn < vnBtns.GetSize(); iBtn++ )
	{
		Button btnCtrl = GetItem(vnBtns[iBtn]);
		if ( btnCtrl )
			btnCtrl.Visible = true;
		BitmapRadioButton btn = GetItem(vnBtns[iBtn]);
		vector<string> vsTips(1);
		vsTips[0] = vsBtnTips[iBtn];
		if ( btn )
		{
			btn.Init(1, vnBitmaps[iBtn], 16, vsTips);
		}
	}
	return TRUE;
}
///end EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL


///Sophy 6/25/2010 ORG-23-S8 XY_INTERP_FOR_GADGET_TOOL_DLG
#define	STR_INTERP_DLG_NAME		"Interpolate Y From X"
InterpXYDlg::InterpXYDlg() : ResizeDialog(IDD_QUICK_FIT_FINDXY, "ODlg8")
{
}

int	InterpXYDlg::DoModalEx(InterpParams& stParams, HWND hWndParent)
{
	m_stParams = stParams;
	InitMsgMap();
	return ResizeDialog::DoModal(hWndParent);
}

BOOL	InterpXYDlg::OnInitDialog()
{
	Text = _L(STR_INTERP_DLG_NAME); //update the dialog title
	InitControls();
	LoadSettings();
	InitRangeText();
	UpdateButtonState();
	m_bFocusReset = false;
	return true;
}

BOOL	InterpXYDlg::OnReady()
{
	SetInitReady();
	return TRUE;
}

BOOL	InterpXYDlg::OnIdle()
{
	if ( !m_bFocusReset )
	{
		SetFocus(m_edtX.GetSafeHwnd());
		m_bFocusReset = true;
	}
	return TRUE;
}
BOOL	InterpXYDlg::OnDestroy()
{
	SaveSettings();
	return TRUE;
}

BOOL	InterpXYDlg::OnOutputChange(Control ctrl)
{
	if ( m_btnOutputScriptWindow.Value )
		m_nOutputTarget = OUTPUT_TO_SCRIPTWINDOW;
	else if ( m_btnOutputResultLog.Value )
		m_nOutputTarget = OUTPUT_TO_RESULTLOG;
	else if ( m_btnOutputWorksheet.Value )
		m_nOutputTarget = OUTPUT_TO_WORKSHEET;
	else
		ASSERT(false);
	UpdateButtonState();
	return TRUE;
}

BOOL	InterpXYDlg::OnClickInterp(Control ctrl)
{
	vector vInput, vOutput;
	if ( Calculate(vInput, vOutput) > 0 )
	{
		string strOutput;
		vector<string> vsOutput;
		convert_double_vector_to_string_vector(vOutput, vsOutput, vOutput.GetSize());
		strOutput.SetTokens(vsOutput, ';');
		m_edtY.Text = strOutput;
	}
	return TRUE;
}

///Sophy 6/30/2010 ORG-23-P6 PROPER_CHECK_WHEN_OUTPUT_TO_WORKSHEET
static	void _check_report_worksheet(TreeNode& trReport, LPCSTR lpcszWorksheetName, int nOutputTarget)
{
	if ( OUTPUT_TO_WORKSHEET == nOutputTarget )
	{
		out_tree_to_wks(trReport, lpcszWorksheetName, CREATE_HIDDEN | CREATE_LOAD_1ST_LAYER_ONLY);
	}
}
///end PROPER_CHECK_WHEN_OUTPUT_TO_WORKSHEET
BOOL	InterpXYDlg::OnClickOutput(Control ctrl)
{
#define	STR_NEXT_LINE	"\r\n"

	vector vInput, vOutput;
	if ( Calculate(vInput, vOutput) > 0 )
	{
		string strComments, strOutput, strRng = "";
		XYRange xySrc;
		m_dpSrc.GetDataRange(xySrc, m_stParams.ni1, m_stParams.ni2);
		if ( xySrc )
			strRng = xySrc.GetDescription(GETLC_MAIN_OBJ_ONLY | GETLC_COL_LONG_NAME | GETLC_INCLUDE_LOOSE_DATA);
		strComments.Format(_L("Interpolate Y from X on %s"), strRng);
		strOutput = strComments + STR_NEXT_LINE + "X\t\tY" + STR_NEXT_LINE;
		string strWorksheet = m_edtWorksheetName.Text;
		for ( int ii = 0; ii < vInput.GetSize(); ii++ )
		{
			double dInput = vInput[ii], dOutput = vOutput[ii];
			strOutput += get_value_by_format(m_dpSrc, dInput) + "\t\t" + ftoa(dOutput, "*") + STR_NEXT_LINE;
			///Sophy 6/30/2010 ORG-23-S9 BETTER_LABELS_FOR_RESULT_CURVE
			GETN_TREE(trReport)
			GETN_NUM(X, _L("Specified X"), dInput)
			GETN_CURRENT_SUBNODE.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_X);
			GETN_NUM(Y, _L("Found Y"), dOutput)
			GETN_CURRENT_SUBNODE.SetAttribute(STR_COL_DESIGNATION_ATTRIB, OKDATAOBJ_DESIGNATION_Y);
			GETN_CURRENT_SUBNODE.SetAttribute(STR_COL_COMMENTS_LABEL_ATTRIB, strComments);
			///end BETTER_LABELS_FOR_RESULT_CURVE
			///Sophy 6/30/2010 ORG-23-P6 PROPER_CHECK_WHEN_OUTPUT_TO_WORKSHEET
			//out_tree_to_wks(trReport, strWorksheet, CREATE_HIDDEN | CREATE_LOAD_1ST_LAYER_ONLY);
			_check_report_worksheet(trReport, strWorksheet, m_nOutputTarget);
			///end PROPER_CHECK_WHEN_OUTPUT_TO_WORKSHEET
		}
		switch( m_nOutputTarget )
		{
		case OUTPUT_TO_SCRIPTWINDOW:
			LT_execute("type -a"); //show script window
			strOutput.Write(WRITE_SCRIPT_WINDOW);
			break;
			
		case OUTPUT_TO_RESULTLOG:
			Project.OutStringToResultsLog(strOutput, false);
			break;
			
		case OUTPUT_TO_WORKSHEET:
			//already output above...
			UpdateButtonState(); //enable "Go" if possible
			break;
			
		default:
			ASSERT(false);
			break;
		}
		return TRUE;
	}
	return FALSE;
}

int		InterpXYDlg::GetInput(vector& vInput)
{
	vInput.SetSize(0);
	string strInput = m_edtX.Text;
	vector<string> vsXs;
	int nSize = strInput.GetTokens(vsXs, ';');
	for ( int ii = 0; ii < nSize; ii++ )
	{
		double dValue = get_value_by_format(m_dpSrc, vsXs[ii]);
		vInput.Add(dValue);
	}
	return nSize;
}

int		InterpXYDlg::GetOutput(const vector& vInput, vector& vOutput)
{
	vector vInputLocal;
	vInputLocal = vInput;
	vOutput.SetSize(vInputLocal.GetSize());
	if ( vInputLocal.GetSize() > 0 )
	{
		vector vX, vY;
		if ( !m_dpSrc || m_dpSrc.GetDataPoints(m_stParams.ni1, m_stParams.ni2, vX, vY) <= 0 )
		{
			ASSERT(false);
			return -1;
		}
		
		GraphLayer gl;
		m_dpSrc.GetParent(gl);
		int nXScale = LINEAR_SPACE, nYScale = LINEAR_SPACE;
		nXScale = gl.X.Type;
		nYScale = gl.Y.Type;
		
		vInputLocal = real_space(vInputLocal, nXScale);
		vX = real_space(vX, nXScale);
		vY = real_space(vY, nYScale);
		;
		int nRet = ocmath_interpolate(vInputLocal, vOutput, vInputLocal.GetSize(), vX, vY, vX.GetSize(), m_stParams.nMethod, m_stParams.dSmoothFactor, NULL, NULL, 0, m_stParams.nBoundary);
		if ( OE_NOERROR != nRet )
			return -2;
		vInputLocal = real_inv_space(vInputLocal, nXScale);
		vOutput = real_inv_space(vOutput, nYScale);
	}
	return vOutput.GetSize();
}

int		InterpXYDlg::Calculate(vector& vInput, vector& vOutput)
{
	vInput.SetSize(0);
	vOutput.SetSize(0);
	if ( GetInput(vInput) > 0 )
		GetOutput(vInput, vOutput);
	
	return vOutput.GetSize();
}

BOOL	InterpXYDlg::OnClickGoToWorksheet(Control ctrl)
{
	string strWorksheet = m_edtWorksheetName.Text;
	Worksheet wks(strWorksheet);
	if ( wks.IsValid() )
	{
		wks.CheckShowActivate();
	}
	return TRUE;
}

BOOL	InterpXYDlg::OnOutputWorksheetChange(Control ctrl)
{
	return TRUE;
}

void	InterpXYDlg::InitControls()
{
	m_btnOutputScriptWindow = GetItem(IDC_OUTPUT_TO_SCRIPTWINDOW);
	m_btnOutputResultLog = GetItem(IDC_OUTPUT_TO_RESULTLOG);
	m_btnOutputWorksheet = GetItem(IDC_OUTPUT_TO_WORKSHEET);
	m_edtWorksheetName = GetItem(IDC_OUTPUT_WORKSHEET_NAME);
	m_edtX = GetItem(IDC_X_VALUES);
	m_edtY = GetItem(IDC_Y_VALUES);
	RichEdit edHint = GetItem(IDC_FINDXY_HINT);
	if(edHint)
	{
		edHint.Enable = false;
		edHint.Text = _L("Enter semicolon separated values to find multiple values.");
		edHint.SetTextColor(0, -1, color_index_to_rgb(SYSCOLOR_BLUE));
	}
	
	m_edtY.ReadOnly = TRUE;	///Sophy 6/30/2010 ORG-23-S0 MAKE_EDIT_CONTROL_READONLY_TO_ALLOW_COPY
	
	Button btnInterp = GetItem(IDC_BTN_INTERP);
	btnInterp.Text = _L("Interpolate");
}

void	InterpXYDlg::InitRangeText()
{
	Control ctrlRangeHints = GetItem(IDC_RANGE_HINTS);
	GraphLayer glSrc = Project.ActiveLayer();
	if ( glSrc )
	{
		m_dpSrc = glSrc.DataPlots(m_stParams.nPlotIndex);
		if ( m_dpSrc )
		{
			vector vX, vY;
			if ( m_dpSrc.GetDataPoints(m_stParams.ni1, m_stParams.ni2, vX, vY) <= 0 )
			{
				ASSERT(false);
				return;
			}
			double dMinX, dMaxX, dMinY, dMaxY;
			vX.GetMinMax(dMinX, dMaxX);
			vY.GetMinMax(dMinY, dMaxY);
			string strRngHints;
			strRngHints.Format("X Range = [%s, %s]\r\nY Range = [%s, %s]", get_value_by_format(m_dpSrc, dMinX), get_value_by_format(m_dpSrc, dMaxX), ftoa(dMinY), ftoa(dMaxY));
			ctrlRangeHints.Text = strRngHints;
		}
	}
}

void	InterpXYDlg::LoadSettings()
{
	m_nOutputTarget = LoadSetting("OutputTarget", 0, STR_INTERP_DLG_NAME);
	m_btnOutputScriptWindow.Value = (OUTPUT_TO_SCRIPTWINDOW == m_nOutputTarget);
	m_btnOutputResultLog.Value = (OUTPUT_TO_RESULTLOG == m_nOutputTarget);
	m_btnOutputWorksheet.Value = (OUTPUT_TO_WORKSHEET == m_nOutputTarget);
	
	string strWorksheet;
	dlg_load_registry(STR_INTERP_DLG_NAME, "OutputWorksheet", strWorksheet, "[InterpXY]Result");
	m_edtWorksheetName.Text = strWorksheet;
}

void	InterpXYDlg::SaveSettings()
{
	SaveSetting("OutputTarget", m_nOutputTarget, STR_INTERP_DLG_NAME);
	dlg_save_to_registry(STR_INTERP_DLG_NAME, "OutputWorksheet", m_edtWorksheetName.Text);
}

void	InterpXYDlg::UpdateButtonState()
{
	m_edtWorksheetName.Enable = m_btnOutputWorksheet.Value;
	string strWorksheet = m_edtWorksheetName.Text;
	BOOL bEnable = m_edtWorksheetName.Enable;
	if ( bEnable )
	{
		Worksheet wks(strWorksheet);
		bEnable = wks.IsValid();
	}
	Button btnGotoReport = GetItem(IDC_BTN_GO_TO_REPORT);
	btnGotoReport.Enable = bEnable;
}

void	OpenInterpXYDlg(InterpParams& stParams)
{
	InterpXYDlg dlg;
	dlg.DoModalEx(stParams, GetWindow());
	return;
}

///end XY_INTERP_FOR_GADGET_TOOL_DLG