/*------------------------------------------------------------------------------*
 * File Name:				 													*
 * Creation: CPY 8/10/2006														*
 * Purpose: OriginC Source C file												*
 * Copyright (c) Originlab Corp. 2006											*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 *	CPY 10/27/06 COLOR_SPECTRUM_PLOT											*
 *	RVD 1/23/2007 SCROLLBAR_CONTEXT_MENU										*
 *	Hong 04/24/07 v8.0607 NEED_UPDATE_SCRIPT_IF_HAVE							*
 * 	Hong 04/25/07 v8.0608 MOVE_TO_PFM_UTILS										*
 *	Hong 04/25/07 QA80-9457-P13 FIX_TEXT_CAN_FLOAT_OUT_OF_LAYER					*
 *	Sim 07-17-2007 ADD_XY_SCALER_OBJECT											*
 *	Hong 11/10/07 QA80-10671 FIX_PCLAMP_XY_SCALER_HAVE_DIFF_UNITS				*
 *	Cloud 11/30/07 COORDINATE_SHOULD_BE_DOUBLE									*
 *	YuI 02/05/08 WORK_ON_SPFW													*
 *	Hong 02/26/08 v8.0812 USING_CLASS_CENTRALIZE_CODE_OF_PEAK_CONTROL			*
 *	Jasmine 03/15/08 CP_ASK_MOVE_CPEAKSPREVIEWHELPER_FROM_SPFM_UTILS			*
 *	Hong 03/20/08 v8.0828 EMPTY_DESTRUCTOR_LEAD_XF_PKFIND_LINKING_ERROR_UNEXPECTED
 *	Hong 03/26/08 v8/0832b PA_PEAKS_DEL_REQUIRE_FOLLOWING_DATA_SUPPORT			*
 *	Folger 04/25/08 IMPROVE_MODIFY_AND_DELETE_PEAKS_IN_NANOSIZER				*
 *  Sandy 2008-9-9 QA80-12141 XYRANGE_PLOT_LABELS_WITHOUT_L_COL 				*
 *	CPY 9/12/08 ADD_FFT_TOOL_XF_SHOULD_NOT_ALLOW_RECT_ROTATE_ETC				*
 *	Sophy 9/13/2008 GRAPH_OBJ_TOOL_BASE_CLASS									*
 *	YuI 09/16/08 QA70-12204 POSITION_CONTROL_FOR_CONNECT_TO						*
 *	CPY 9/17/08 CLEANUP_CODE_RELATED_TO_USING_BASE_CLASS_SET_TREE				*
 *	CPY 9/17/08 FFT_TOOL_CLEANUP_AFTER_FISHER_EDIT								*
 *	CPY 9/23/08 QA70-12263 RECT_WITH_BUTTON_NOT_DELETABLE						*
 *	CPY 9/24/08 FINE_ADJUSTMENT_ON_BUTTON_POSITIONS_AS_ATTACHED_GR				*
 *	YuI 09/24/08 QA70-12264 OPTION_TO_SELECT_GR_OBJECT_BEFORE_DATA				*
 *	CPY 9/24/08 CENTER_LABEL_ON_TOOL_AFTER_ROMAN_ADD_SUCH_SUPPORT				*
 *	Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS			*
 *	Hong 12/12/08 v8.0986 CLEAN_MAGIC_NUMBER									*
 *	Sandy 2008-12-17 ADD_PROGRESSBOX_AND_GIVE_USER_FEEDBACK_AND_CANCEL_WHEN_THE_PROGRESS_SLOW
 *	Hong 12/26/08 v8.0991 IMPROVE_SPEED											*
 *	Kenny 05/04/2009 ADD_FUNC_FOR_USE_OF_VERTICAL_CURSOR						*
 *	Folger 05/06/09 MAX_SUGGEST_BIGGER_FONT_SIZE_FOR_GRAPH_OBJ_TEXT				*
 *	Sophy 6/12/2009 IMPROVE_RISETIME_TOOL_FOR_OSCILLOSCOPE_SIGNAL_PROCESSING	*
 *	Fisher 7/20/09 QA80-13975 HANDLE_RESCALE_EVENT_FOR_GRAPH_OBJ_TOOL			* 
 *	CPY 7/20/09 QA70-13575 HANDLE_RESCALE_EVENT_FOR_GRAPH_OBJ_TOOL				*
 *	Sim 08-14-2009 QA81-14124 FIX_GUI_CHANGE_CAUSE_PREVIEW_RECURSIVELY_REFRESH	*
 *	Sophy 8/19/2009 DUMP_RESULT_WITH_DOUBLE_USE_GLOBAL_DECIMAL_DIGIT_SETTINGS	*
 *	Sophy 8/21/2009 QA80-14175 CREATE_ALL_NODES_IN_ONE_TREE_TO_GET_RID_OF_OPTIONS_BRANCH	*
 *	Sophy 8/26/2009 QA80-14169 MAKE_GRAPHOBJECT_FOR_PROGRAMMING_CONTROL_PRINTABLE
 *	Sophy 11/26/2009 EVT_HANDLER_IN_TREENODE_INVALID_WHEN_RESTART_ORIGIN		*
 *	Sophy 12/4/2009 QA80-14799 EXPOSE_DATAMASK_EVENT_TO_OC_GRAPHOBJECT			*
 *	Sophy 12/14/2009 QA80-14686-P2 DATAPLOT_GET_DATAPOINTS_NEED_TO_SKIP_MASKED_DATA
 *	Sophy 12/17/2009 QA80-14598-P4 RISE_TIME_TOOL_NEED_CREATE_LONGNAME_IN_RESULT_COLUMN
 *	Kenny 12/24/2009 QA81-14875-P2 PROGRESS_BAR_IN_BUILTIN_TOOL_SHOULD_NOT_KEEP_TOPMOST*
 *	Sophy 1/4/2010 QA80-14904-S1 SUPPORT_FLEXIBLE_ATTACHED_GROBJ_FOR_ROI_TOOLS	*
 *	Folger 01/23/10 QA81-14903 FIT_CURVE_LINE_IN_QUICK_FIT_SHOULD_NOT_DRAW_EDGE_WHEN_SELECT_ROI
 *  Iris 2/09/2010 FIX_COMPILE_ERR_WHEN_INCLUDE_GROBJUTILS_H_FILE				*
 *	RVD 2/9/2010 qa70-15085 SCALEIN_PA_PEAK_RECT_LIMITED						*
 *	Jasmine 03/18/10 QA81-14861 IMAGE_PROFILE_WANT_POLYLINE						*
 *------------------------------------------------------------------------------*/
 
#include <Origin.h>
/// RVD 1/23/2007 SCROLLBAR_CONTEXT_MENU
#include <Control.h>
#include "OriginEvents.h"
/// end SCROLLBAR_CONTEXT_MENU
#include "grobj_utils.h"
#include "curve_utils.h" /// Hong 02/26/08 v8.0812 USING_CLASS_CENTRALIZE_CODE_OF_PEAK_CONTROL
#pragma labtalk(0)

static void _percent_to_real(double& x, Layer& lay, bool bX)
{
	string strLT;
	if(bX)
		strLT.Format("_temp_val = x1 + (%g) * (x2-x1)/100", x);
	else
		strLT.Format("_temp_val = y1 + (%g) * (y2-y1)/100", x);
	lay.LT_execute(strLT);
	LT_get_var("_temp_val", &x);
	LT_execute("del -v _temp_val");
}
// return true if updated
static bool _check_convert_pos(Layer& lay, vector& vx, bool bPercent, int nAttach, bool bX)
{
	if(bPercent && nAttach == 2) // 2 = scale
	{
		for(int ii = 0; ii < vx.GetSize(); ii++)
		{
			double x = vx[ii];
			_percent_to_real(x, lay, bX);
			vx[ii] = x;
		}
		return true;
	}
	else if(bPercent && nAttach != 2)
	{
		vx/=100.; // Roman said internally using ratio
		return true;
	}
	return false;
}

bool add_text(Layer& lay, GraphObject& go, double x, double y, LPCSTR lpcszText, int nFontSize, bool bPercent, int nAttach)
{
	if(bPercent)
	{
		_percent_to_real(x, lay, true);
		_percent_to_real(y, lay, false);
	}
	go = lay.CreateGraphObject(GROT_TEXT);
	go.Attach = nAttach;
	go.Text = lpcszText;
	//printf("x=%g,y=%g, dx=%g,dy=%g\n", x, y, go.DX, go.DY);
	go.X = x + go.DX/2;// assume linear scale
	go.Y = y + go.DY/2;
	if(nFontSize > 0) // assume cannot set to 0
	{
		Tree tr;
	 	tr.Root.Font.Size.nVal = nFontSize;
		//go.UpdateThemeIDs(tr.Root);
		//go.ApplyFormat(tr, true, true);
		int nErr = go.UpdateThemeIDs(tr.Root);
		if(nErr == 0)
		{
			go.ApplyFormat(tr, true, true);
			return true;
		}
		out_int("err = ", nErr);
		return false;		
	}
	return true;
}
	
/// Iris 12/06/2006 v8.0519 CORRECT_XY_RANGE_LINE_IN_XYZGRIDDING
//bool add_line(Layer& lay, GraphObject& go, double x0, double y0, int nAttach, int nDirection, bool bSpan, bool bPercent, double x1, double y1, int nColor)
bool add_line(Layer& lay, GraphObject& go, double x0, double y0, int nAttach, int nDirection, bool bSpan, bool bPercent, double x1, double y1, int nColor, LPCSTR lpcszName)
///end CORRECT_XY_RANGE_LINE_IN_XYZGRIDDING
{
	go = lay.CreateGraphObject(GROT_LINE);
	go.Attach = nAttach;
	Tree tr;
	tr = go.GetFormat(FPB_DATA, FOB_ALL, true, true);
	vector vx(2), vy(2);
	if(bSpan)
	{
		x1=x0;
		y1=y0;
	}
	vx[0] = x0, vx[1] = x1;
	vy[0] = y0, vy[1] = y1;
	_check_convert_pos(lay, vx, bPercent, nAttach, true);
	_check_convert_pos(lay, vy, bPercent, nAttach, false);
	tr.Root.Direction.nVal = nDirection;
	tr.Root.Span.nVal = bSpan?1:0;
	tr.Root.Data.X.dVals = vx;
	tr.Root.Data.Y.dVals = vy;
	tr.Root.Color.nVal = nColor;
	//go.UpdateThemeIDs(tr.Root);
	//go.ApplyFormat(tr, true, true);
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
	}
	else
	{
		out_int("err = ", nErr);
		return false;
	}
	/// Iris 12/06/2006 v8.0519 CORRECT_XY_RANGE_LINE_IN_XYZGRIDDING
	if(lpcszName && lstrlen(lpcszName) > 0)
		go.SetName(lpcszName);
	///end CORRECT_XY_RANGE_LINE_IN_XYZGRIDDING

	return true;
}

///Jasmine 03/18/10 QA81-14861 IMAGE_PROFILE_WANT_POLYLINE
bool add_polyline(Layer& lay, GraphObject& goPolyLine, const vector& vx, const vector& vy, int nAttach/* = ATTACH_TO_SCALE*/, bool bPercent/* = true*/, int nColor/* = SYSCOLOR_RED*/, LPCSTR lpcszName/* = NULL*/)
{
	if(!lay || !vx || !vy || vx.GetSize() < 1 || vy.GetSize() < 1)
		return false;
	
	goPolyLine = lay.CreateGraphObject(GROT_POLYLINE);
	goPolyLine.Attach = nAttach;
	
	_check_convert_pos(lay, vx, bPercent, nAttach, true);
	_check_convert_pos(lay, vy, bPercent, nAttach, false);
	
	Tree trFmt;
	trFmt = goPolyLine.GetFormat(FPB_DATA, FOB_ALL, true, true);
	trFmt.Root.Data.X.dVals = vx;
	trFmt.Root.Data.Y.dVals = vy;
	trFmt.Root.Color.nVal = nColor;
	
	int nErr = goPolyLine.UpdateThemeIDs(trFmt.Root);
	if(nErr == 0)
	{
		goPolyLine.ApplyFormat(trFmt, true, true);
	}
	else
	{
		out_int("err = ", nErr);
		return false;
	}

	if(lpcszName && lstrlen(lpcszName) > 0)
		goPolyLine.SetName(lpcszName);

	return true;
}
///End IMAGE_PROFILE_WANT_POLYLINE

///Sandy 2007-3-23 CHANGE_RECT_POSITION_VALUE_AS_DOUBLE
//bool add_rect(const Layer& lay, GraphObject& go, int x0, int y0, int x1, int y1, int nFillColor, int nAttach, int nDirection, bool bSpan, bool bPercent) //= 1, 2, LN_VERTICAL, true
bool add_rect(const Layer& lay, GraphObject& go, double x0, double y0, double x1, double y1, int nFillColor, int nAttach, int nDirection, bool bSpan, bool bPercent) 
{
	if(!lay.IsValid())
		return false;
	go = lay.CreateGraphObject(GROT_RECT);
	go.Attach = nAttach;
	vector vx(4), vy(4);

	vx[0] = x0, vx[1] = x1; vx[2] = x1; vx[3] = x0; ///---Sim 10-17-2006 CORRECT_VECTOR_VALUE
	vy[0] = y0, vy[1] = y0; vy[2] = y1; vy[3] = y1;
	_check_convert_pos(lay, vx, bPercent, nAttach, true);
	_check_convert_pos(lay, vy, bPercent, nAttach, false);

	Tree tr;
	tr = go.GetFormat(FPB_DATA, FOB_ALL, true, true);
	tr.Root.Direction.nVal = nDirection;
	tr.Root.Span.nVal = bSpan?1:0;
	tr.Root.Data.X.dVals = vx;
	tr.Root.Data.Y.dVals = vy;
	tr.Root.Fill.Color.nVal = nFillColor; ///---Sim 10-17-2006 CORRECT_COLOR_VALUE
	
	tr.Root.States.nVal = GOC_NO_ROTATE | GOC_NO_SKEW | GOC_NO_EDIT | GOC_NO_BORDERSIZE | GOC_NO_IN_PLACE_EDIT; //CPY 9/12/08 ADD_FFT_TOOL_XF_SHOULD_NOT_ALLOW_RECT_ROTATE_ETC	
	//go.UpdateThemeIDs(tr.Root);
	//go.ApplyFormat(tr, true, true);
	//return true;
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}

bool add_polygon(Layer& lay, GraphObject& go, const vector& vxPos, const vector& vyPos, int nAttach, bool bPercent)
{
	if(vxPos.GetSize() < 3 || vxPos.GetSize() != vyPos.GetSize())
		return false;
	go = lay.CreateGraphObject(GROT_POLYGON);
	go.Attach = nAttach;
	Tree tr;
	//tr = go.GetFormat(FPB_DATA, FOB_ALL, true, true);
	vector vx, vy;
	vx = vxPos;
	vy = vyPos;
	_check_convert_pos(lay, vx, bPercent, nAttach, true);
	_check_convert_pos(lay, vy, bPercent, nAttach, false);
	tr.Root.Data.X.dVals = vx;
	tr.Root.Data.Y.dVals = vy;
	//go.UpdateThemeIDs(tr.Root);
	//go.ApplyFormat(tr, true, true);
	//return true;
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}

///Sandy 2007-1-18 add position info for initialize.
//bool make_slider(GraphObject& go, LPCSTR lpcszCallbackFuncName, int index, LPCSTR lpcszName)
bool make_slider(GraphObject& go, LPCSTR lpcszCallbackFuncName, int index, LPCSTR lpcszName, double dPosPercent)
{
	if(go)
	{
		///Add by Sandy to make sure slider only attach to Line Object
		int nType;
		go.GetObjectType(&nType);
		if(nType!=GROT_LINE)
			return false;
		
		/*
		go.Info.Add("Slider");
		go.Info.Slider.AddSection("Handler");
		go.Info.Slider.Handler.Name$ = lpcszCallbackFuncName;//"slider_handler";
		*/
		Tree tr;
		tr.Handler.strVal = lpcszCallbackFuncName;
		tr.Info.index.nVal = index;
		tr.Info.name.strVal = lpcszName;
		
		//Add by Sandy
		//---- CPY 2/14/07 SLIDER_POSITION, change name as percent is misleading, as it is used as fraction
		//tr.percent.dVal = dPosPercent; 
		tr.Position.dVal = dPosPercent;
		//----
		//end 
		
		return go.AttachXFunction("gslider", tr);
	}
	return false;
}

///Sandy 2007-2-12 add modify slider function to speed up preview
bool modify_slider(GraphObject& go,  double dPosPercent)
{

	if(dPosPercent < 0 || dPosPercent > 1)
	{
		return false;
	}
	if(go)
	{
		///Add by Sandy to make sure slider only attach to Line Object
		int nType;
		go.GetObjectType(&nType);
		if(nType!=GROT_LINE)
			return false;		
		Tree tr;
		//tr = go.GetFormat(FPB_ALL | FPB_DATA, FOB_ALL, true, true);
		//out_tree(tr);
		vector vx, vy;
		vx.SetSize(1);
		vx[0] = dPosPercent; vy=vx;
		// Anchor1 is event info, this has to match gslider XF
		// so this works only if slider is created using gslider XF
		tr.Root.Anchors.Anchor2.Data.X.dVals = vx;
		tr.Root.Anchors.Anchor2.Data.Y.dVals = vy;
		//go.UpdateThemeIDs(tr.Root);
		//go.ApplyFormat(tr, true, true);
		//
		//return true;
		int nErr = go.UpdateThemeIDs(tr.Root);
		if(nErr == 0)
		{
			go.ApplyFormat(tr, true, true);
			return true;
		}
		out_int("err = ", nErr);
		return false;		
	}
	
	return false;

}
///end
//----- CPY 9/23/08 QA70-12263 RECT_WITH_BUTTON_NOT_DELETABLE 
//bool set_LT_script(GraphObject& go, LPCSTR lpcszScript, int nExecMode)
bool set_LT_script(GraphObject& go, LPCSTR lpcszScript, int nExecMode, int nSetDeletable)
//-----
{
	if(!go)
		return false;
	
	//----- CPY 9/23/08 QA70-12263 RECT_WITH_BUTTON_NOT_DELETABLE 
	DWORD dwOldStats;
	if(nSetDeletable >= 0)
	{
		Tree tr1;
		tr1 = go.GetFormat(FPB_OTHER, FOB_ALL, true, true);
		dwOldStats = tr1.Root.States.nVal;
	}
	//-----
	
	string str = lpcszScript;
	Tree tr;
	tr.Root.Event.nVal = nExecMode;
	///---Sim 08-14-2009 QA81-14124 FIX_GUI_CHANGE_CAUSE_PREVIEW_RECURSIVELY_REFRESH
	//tr.Root.Script.strVal = str;
	if ( lpcszScript != NULL )
		tr.Root.Script.strVal = str;
	///---END QA81-14124 FIX_GUI_CHANGE_CAUSE_PREVIEW_RECURSIVELY_REFRESH
	//go.UpdateThemeIDs(tr.Root);
	//go.ApplyFormat(tr, true, true);
	//return true;
	
	//----- CPY 9/23/08 QA70-12263 RECT_WITH_BUTTON_NOT_DELETABLE 
	if(nSetDeletable >= 0)
	{
		DWORD dwBits = dwOldStats;
		if(nSetDeletable > 0)
		{
			dwBits = dwOldStats|GOC_REV_USER_DEL;
		}
		else
		{
			dwBits = dwOldStats & (~GOC_REV_USER_DEL);		
		}
		
		tr.Root.States.nVal = dwBits;
	}
	//-----

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


bool add_polygon_cntrl(const GraphLayer& gl, LPCSTR lpcszName, const vector& vx, const vector& vy, LPCSTR lpcszSecName, bool bKeepInside)
{
	GraphObject go;
	gl.RemoveGraphObject(lpcszName);
	if(add_polygon(gl, go, vx, vy, 0, true))
	{
		go.SetName(lpcszName);
		Tree tr;
		/// YuI 09/24/08 QA70-12264 OPTION_TO_SELECT_GR_OBJECT_BEFORE_DATA
		tr = go.GetFormat(FPB_OTHER, FOB_ALL, true, true);
		/// end OPTION_TO_SELECT_GR_OBJECT_BEFORE_DATA
		tr.Root.Fill.Color.nVal = SYSCOLOR_CYAN;
		tr.Root.KeepInside.nVal = bKeepInside?1:0;
		/// YuI 09/24/08 QA70-12264 OPTION_TO_SELECT_GR_OBJECT_BEFORE_DATA
		//	tr.Root.States.nVal = GOC_NO_VMOVE|GOC_NO_RESIZE|GOC_NO_ROTATE|GOC_NO_SKEW|GOC_NO_EDIT|GOC_NO_BORDERSIZE;
		_update_go_states_node(tr, GOC_NO_VMOVE|GOC_NO_RESIZE|GOC_NO_ROTATE|GOC_NO_SKEW|GOC_NO_EDIT|GOC_NO_BORDERSIZE, 0);
		/// end OPTION_TO_SELECT_GR_OBJECT_BEFORE_DATA

		
	
		tr.Root.Event.nVal = GRCT_MOVE;
		string strLT;
		strLT.Format("run.section(Graph_Controls,%s)", lpcszSecName);
		tr.Root.Script.strVal = strLT;//"run.section(Graph_Controls,X2ScaleChange)";
	
		//go.UpdateThemeIDs(tr.Root);
		//go.ApplyFormat(tr, true, true);
		//return true;
		int nErr = go.UpdateThemeIDs(tr.Root);
		if(nErr == 0)
		{
			go.ApplyFormat(tr, true, true);
			return true;
		}
		out_int("err = ", nErr);
		return false;		
	}
	return false;
}

//----- CPY 11/15/06
bool set_auto_hide(GraphObject& go, bool bSet)
{
	Tree tr1, tr;
	tr1 = go.GetFormat(FPB_OTHER, FOB_ALL, true, true);
	DWORD dw = tr1.Root.States.nVal;
	if(bSet)
		dw |= GOC_AUTOHIDE;
	else
		dw &=~GOC_AUTOHIDE;
	
	tr.Root.States.nVal = dw;
	//go.UpdateThemeIDs(tr.Root);
	//go.ApplyFormat(tr, true, true);
	//return true;
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}
//-----

bool disable_go_rotate_skew(GraphObject& go, bool bNoRotate, bool bNoSkew,  bool bEnable)
{
	//GOC_NO_HMOVE, GOC_NO_VMOVE, GOC_NO_RESIZE|GOC_NO_ROTATE|GOC_NO_SKEW|GOC_NO_EDIT)
	Tree tr1, tr;
	tr1 = go.GetFormat(FPB_OTHER, FOB_ALL, true, true);
	DWORD dwOldStats = tr1.Root.States.nVal;
	
	DWORD dwBits = 0;
	if(!bEnable)
	{
		dwBits = dwOldStats|GOC_NO_ROTATE|GOC_NO_SKEW;
		if(bNoRotate) dwBits |= GOC_NO_ROTATE;
		if(bNoSkew) dwBits |= GOC_NO_SKEW;
	}
	else
	{
		dwBits = dwOldStats & (~GOC_NO_STATE);		
	}

	tr.Root.States.nVal = dwBits;

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

bool disable_go_move(GraphObject& go, bool bHorz, bool bVert, bool bKeepInside, bool bEnable)
{
	Tree tr1, tr;
	tr1 = go.GetFormat(FPB_OTHER, FOB_ALL, true, true);
	DWORD dwOldStats = tr1.Root.States.nVal;
	
	tr.Root.KeepInside.nVal = bKeepInside?1:0;
	
	DWORD dwBits;
	if(!bEnable)
	{
		dwBits = dwOldStats | GOC_NO_RESIZE|GOC_NO_ROTATE|GOC_NO_SKEW|GOC_NO_EDIT|GOC_NO_BORDERSIZE;
		if(bHorz) dwBits |= GOC_NO_HMOVE;
		if(bVert) dwBits |= GOC_NO_VMOVE;
	}
	/// Iris 12/18/2006 v8.0527 XYZ2MAT_DISABLE_RECT_MOVEMENT_EXCEPT_TPS_METHOD
	else
	{
		dwBits = dwOldStats & (~GOC_NO_STATE);		
	}
	///end XYZ2MAT_DISABLE_RECT_MOVEMENT_EXCEPT_TPS_METHOD
	
	tr.Root.States.nVal = dwBits;
	//go.UpdateThemeIDs(tr.Root);
	//go.ApplyFormat(tr, true, true);
	//return true;
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}

bool set_go_border_color(GraphObject& go, int nColor)
{
	Tree tr;
	tr = go.GetFormat(FPB_STYLE_COLOR, FOB_ALL, true, true);
	tr.Root.Border.Color.nVal = nColor;
	//go.UpdateThemeIDs(tr.Root);
	//go.ApplyFormat(tr, true, true);
	//return true;
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}

bool set_go_color(GraphObject& go, int nColor)
{
	Tree tr;
	tr = go.GetFormat(FPB_STYLE_COLOR, FOB_ALL, true, true);
	tr.Root.Color.nVal = nColor;
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}

bool get_go_color(const GraphObject& go, int& nColor)
{
	if( !go )
		return false;
	
	Tree tr;
	tr = go.GetFormat(FPB_STYLE_COLOR, FOB_ALL, true, true);
	TreeNode trColor = tr.Root.Fill.Color? tr.Root.Fill.Color : tr.Root.Color;
	if( trColor )
	{
		nColor = trColor.nVal;
		return true;	
	}
	
	ASSERT(false);
	return false;
}

bool set_go_behind_data(GraphObject& go, bool bBehindData)
{
	Tree tr;
	//tr = go.GetFormat(FPB_OTHER, FOB_ALL, true, true);
 	tr.Root.BehindData.nVal = bBehindData? 1:0;

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

}

/// YuI 09/24/08 QA70-12264 OPTION_TO_SELECT_GR_OBJECT_BEFORE_DATA
static void _update_go_states_node(TreeNode& tr, DWORD dwOn, DWORD dwOff)
{
	DWORD dwStates = 0;
	if( tr.Root && tr.Root.States )
		dwStates = tr.Root.States.nVal;
	
	dwStates |= dwOn;
	dwStates &= ~dwOff;
	tr.Root.States.nVal = dwStates;
}


bool set_go_hittest_before_data(GraphObject& go, bool bHittestBeforeData)
{
	Tree tr;
	tr = go.GetFormat(FPB_OTHER, FOB_ALL, true, true);
	if( bHittestBeforeData )
		_update_go_states_node(tr, GOC_HITTEST_BEFORE_DATA, 0);
	else
		_update_go_states_node(tr, 0, GOC_HITTEST_BEFORE_DATA);
	
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}
/// end OPTION_TO_SELECT_GR_OBJECT_BEFORE_DATA

#ifdef NEW_FEATURE_VERTICAL_CURSOR
///Kenny 05/04/2009 ADD_FUNC_FOR_USE_OF_VERTICAL_CURSOR
bool update_go_states(GraphObject& go, DWORD dwStateAdd, DWORD dwStateRemove /*= 0*/)
{
	Tree tr;
	const BOOL bGetTagNames = TRUE;
	const BOOL bRelative = TRUE;
	tr = go.GetFormat(FPB_OTHER, FOB_ALL, bGetTagNames, bRelative);

	_update_go_states_node(tr, dwStateAdd, dwStateRemove);

	int nErr = go.UpdateThemeIDs(tr.Root);
	if(0 == nErr)
	{
		const BOOL bRepaint = TRUE;
		go.ApplyFormat(tr, bRepaint, bRelative);
		return true;
	}
	return false;
}
///End ADD_FUNC_FOR_USE_OF_VERTICAL_CURSOR
#endif // NEW_FEATURE_VERTICAL_CURSOR

//----- CPY 10/19/06 PCLAMP_TAGS
//	GTB_NONE, GTB_LINE, GTB_SHADOW,
//
bool set_text_border(GraphObject& grText, int nType, int nFillColor)
{
	Tree tr;
 	tr.Root.Background.Shadow.Style.nVal = GTB_SHADOW == nType? 1:0;
 	tr.Root.Background.Border.Width.dVal = GTB_LINE == nType? 0.5:0;
 	tr.Root.Background.Border.Color.nVal = GTB_LINE == nType? SYSCOLOR_BLACK : INDEX_COLOR_TRANSPARENT;
 	if(nType != GTB_NONE)
 		tr.Root.Background.Fill.Color.nVal = nFillColor;
	//grText.UpdateThemeIDs(tr.Root);
	//grText.ApplyFormat(tr, true, true);
	//return true;
	int nErr = grText.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		grText.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}

bool set_text_link_LT_var(GraphObject& grText, bool bLink, int nFontSize)// = 0);
{
	if(!grText)
		return false;
	
	Tree tr;
	tr.Root.LinkToVars.nVal = 1;
	if(nFontSize > 0) // assume cannot set to 0
	{
	 	tr.Root.Font.Size.nVal = nFontSize;
	}
	//grText.UpdateThemeIDs(tr.Root);
	//grText.ApplyFormat(tr, true, true);
	//return true;
	int nErr = grText.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		grText.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}

/// YuI 11/27/06 QA70-9156 MORE_OPTIONS_TO_CONNECTING_OBJECTS
/*
bool add_x_tag(Layer& ll, GraphObject& grLine, GraphObject& grText, double xx, LPCSTR lpcszText)
{
	if(!ll)
		return false;
	
	int nAttach = 2;// to scale
	add_line(ll, grLine, xx, xx, nAttach, LN_VERTICAL, true, false);
	add_text(ll, grText, 50, 50, lpcszText, 16);
	//set_auto_hide(grLine);
	//set_auto_hide(grText);
	set_text_border(grText, GTB_LINE);
	//disable_go_move(grLine, true, true);
	//disable_go_move(grText, true, false);
	grText.X = grLine.X;
	grText.Y = grLine.Y + grLine.DY / 2 + grText.DY / 2;
	/// YuI 11/27/06 QA70-9156 MORE_OPTIONS_TO_CONNECTING_OBJECTS
	//	grText.ConnectTo(grLine, 0, 0, FALSE, TRUE);
	RECT rectConfine = {0, -1000, 0, 1000};
	grLine.ConnectTo(grText, -1, -1, FALSE, OCR_SITE1 | OCR_SITE2, &rectConfine);
	/// end MORE_OPTIONS_TO_CONNECTING_OBJECTS
	return true;
}
*/

bool add_x_tag(Layer& ll, GraphObject& go, GraphObject& grText, double xx, LPCSTR lpcszText, double dWidth)
{
	if(!ll)
		return false;
	
	int nAttach = 2;// to scale
	///---Sim 12-08-2006 FIX_TAG_POSITION
	if( 0 == dWidth )
		//add_line(ll, go, xx, xx, nAttach, LN_VERTICAL, true, false);
		add_line(ll, go, xx, 0, nAttach, LN_VERTICAL, true, false);
	else
		//add_rect(ll, go, xx - dWidth / 2, xx - dWidth / 2, xx + dWidth / 2, xx + dWidth / 2, INDEX_COLOR_TRANSPARENT, nAttach, LN_VERTICAL, true, false);
		add_rect(ll, go, xx - dWidth / 2, 0, xx + dWidth / 2, 100, INDEX_COLOR_TRANSPARENT, nAttach, LN_VERTICAL, true, false);
	///---END FIX_TAG_POSITION
		
	//---CPY 12/6/06 make tag name to be consistent with line name to have same enum sufix
	string strLineName = go.GetName();
	string strPrefix;
	int	nIndex = string_to_prefix_end_number(strPrefix.GetBuffer(MAXLINE), strLineName);
	strPrefix.ReleaseBuffer();
	string strTextName = "tag" + nIndex;
	ll.RemoveGraphObject(strTextName);
	//------
	add_text(ll, grText, 50, 50, lpcszText, 16);
	grText.SetName(strTextName);
	set_text_border(grText, GTB_LINE);
	grText.X = go.X;
	///---Sim 12-08-2006 FIX_TAG_POSITION
	//grText.Y = go.Y + go.DY / 2 + grText.DY / 2;
	grText.Y = go.Y;
	///---END FIX_TAG_POSITION
	/// Hong 04/25/07 QA80-9457-P13 FIX_TEXT_CAN_FLOAT_OUT_OF_LAYER
	// no reason for rectConfine, so remove it
	//RECT rectConfine = {0, -1000, 0, 1000};
	//go.ConnectTo(grText, -1, -1, FALSE, OCR_SITE1 | OCR_SITE2, &rectConfine);
	go.ConnectTo(grText, -1, -1, FALSE, OCR_SITE1 | OCR_SITE2);
	/// end FIX_TEXT_CAN_FLOAT_OUT_OF_LAYER
	return true;
}

bool find_connected_object(const GraphObject& go, GraphObject& goText, int nConnector)
{
	if(nConnector < 0)
		return false;
	vector<uint> vnUIDs;
	if(go.GetConnectedObjects(vnUIDs) > nConnector)
	{
		goText = Project.GetObject(vnUIDs[nConnector]);
		if(goText)
			return true;
	}
	return false;
}

/// end MORE_OPTIONS_TO_CONNECTING_OBJECTS
//-----

bool set_go_width(GraphObject& go, int nWidth)
{
	Tree tr;
	//const BOOL bGetTagNames = TRUE;
	const BOOL bRelative = TRUE;
	//tr = go.GetFormat(FPB_ALL, FOB_ALL, bGetTagNames, bRelative);
	tr.Root.Width.nVal = nWidth;
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(0 == nErr)
	{
		const BOOL bRepaint = TRUE;
		return go.ApplyFormat(tr, bRepaint, bRelative);
	}
	return false;
}

///---Sim 12-07-2006 WORK_FOR_GRAPH_OBJECT_ATTRIBUTE
/*
int get_rect_width(GraphObject& go)//return the min side length
{
	if(!go.IsValid())
		return -1;

	Tree tr;
	tr = go.GetFormat(FPB_ALL, FOB_ALL, true, true);
	int nDirection = tr.Root.Direction.nVal;

	tr = go.GetFormat(FPB_DATA, FOB_ALL, true, true);
	vector vx, vy;
	vx = tr.Root.Data.X.dVals;
	vy = tr.Root.Data.Y.dVals;
	
	int nWidth;
	if(nDirection == LN_HORIZONTAL)
		nWidth = abs(vy[3]-vy[0]);
	else if(nDirection == LN_VERTICAL)
		nWidth = abs(vx[1]-vx[0]);
	
	return nWidth;
}


int get_rect_dir(GraphObject& go)
{
	if(!go.IsValid())
		return -1;

	Tree tr;
	tr = go.GetFormat(FPB_ALL, FOB_ALL, true, true);
	int nDirection = tr.Root.Direction.nVal;

	return nDirection;
}

bool set_rect_border_width(GraphObject& go, int nWidth)
{
	if(!go.IsValid() || nWidth<0)
		return false;

	Tree tr;
	tr = go.GetFormat(FPB_ALL, FOB_ALL, true, true);
	tr.Root.Border.Width.nVal = nWidth;
	
	go.UpdateThemeIDs(tr.Root);
	go.ApplyFormat(tr, true, true);
	return true;
	
}
*/

///Sandy 2006-12-12 modify for more infomation of graphObject's position
//int get_thick_line_width(GraphObject& go)
double get_thick_line_width(GraphObject& go, double* pd1, double* pd2)
{
	if(!go.IsValid())
		return -1;

	
	string strType = go.GetObjectType();
	if ( "Line" == strType )
		return 1;
	else
	if ( "Rectangle" == strType )
	{
		double dd1, dd2;
		
		Tree tr;
		tr = go.GetFormat(FPB_ALL, FOB_ALL, true, true);
		int nDirection = tr.Root.Direction.nVal;
	
		tr = go.GetFormat(FPB_DATA, FOB_ALL, true, true);
		vector vx, vy;
		vx = tr.Root.Data.X.dVals;
		vy = tr.Root.Data.Y.dVals;
		
		//int nWidth;
		double dWidth; //sandy 2006-12-12
		
		if(nDirection == LN_HORIZONTAL)
		{
			///Sandy 2006-12-12
			dd1 = vy[0];
			dd2 = vy[3];
			///end
			dWidth = abs(vy[3]-vy[0]);
			
		}
		else if(nDirection == LN_VERTICAL)
		{
			///Sandy 2006-12-12
			dd1 = vx[1];
			dd2 = vx[0];
			///end
			dWidth = abs(vx[1]-vx[0]);
		}
		if(pd1!=NULL)
			*pd1 = dd1;
		if(pd2!=NULL)
			*pd2 = dd2;
		return dWidth;
	}
	
	return -1; // get error
}
int get_thick_line_dir(GraphObject& go)
{
	if(!go.IsValid())
		return -1;

	Tree tr;
	tr = go.GetFormat(FPB_ALL, FOB_ALL, true, true);
	int nDirection = tr.Root.Direction.nVal;

	return nDirection;
}
///---END WORK_FOR_GRAPH_OBJECT_ATTRIBUTE

bool move_vline(GraphObject& go, double dTop, double dBottom, double x)
{
	// first we need to make sure vline has no restriction for size change
	Tree tr;
	tr.Root.Dimension.Units.nVal = UNITS_PAGE;
	tr.Root.Dimension.Attachment.nVal = 1; // page
	tr.Root.Direction.nVal = 2; // vertical
	tr.Root.Span.nVal = 0;
	Tree tr1;
	tr1 = go.GetFormat(FPB_OTHER, FOB_ALL, true, true);
	DWORD dwOldStats = tr1.Root.States.nVal;
	tr.Root.States.nVal = dwOldStats | GOC_NO_VMOVE|GOC_NO_RESIZE|GOC_NO_ROTATE|GOC_NO_SKEW|GOC_NO_EDIT|GOC_NO_BORDERSIZE;
	vector vx(2);
	vx[0] = vx[1] = x/100.;
	vector vy(2);
	vy[0] = dTop/100.;
	vy[1] = dBottom/100.;
	tr.Root.Data.X.dVals = vx;
	tr.Root.Data.Y.dVals = vy;
	//int iRet = go.UpdateThemeIDs(tr.Root);
	////out_int("err = ", iRet);
	//go.ApplyFormat(tr, true, true);
	//return true;
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}

///add by sandy 2007-4-18
bool move_hline(GraphObject& go, double dLeft, double dRight, double y, int nUnit)
{
	// first we need to make sure vline has no restriction for size change
	Tree tr;
	tr.Root.Dimension.Units.nVal = UNITS_SCALE;
	//tr.Root.Dimension.Attachment.nVal = 1; // page
	tr.Root.Direction.nVal = LN_HORIZONTAL; //
	tr.Root.Span.nVal = 0;
	Tree tr1;
	tr1 = go.GetFormat(FPB_OTHER, FOB_ALL, true, true);
	
	//Sandy 2007-6-11 no need to edit the states in this utility function
	//DWORD dwOldStats = tr1.Root.States.nVal;
	//tr.Root.States.nVal = dwOldStats | GOC_NO_VMOVE|GOC_NO_RESIZE|GOC_NO_ROTATE|GOC_NO_SKEW|GOC_NO_EDIT|GOC_NO_BORDERSIZE;
	//end 
	
	vector vy(2);
	vy[0] = vy[1] = y;
	vector vx(2);
	vx[0] = dLeft;
	vx[1] = dRight;
	tr.Root.Data.X.dVals = vx;
	tr.Root.Data.Y.dVals = vy;
	//int iRet = go.UpdateThemeIDs(tr.Root);
	////out_int("err = ", iRet);
	//go.ApplyFormat(tr, true, true);
	//return true;
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}

///add by sandy 2008-9-18
bool move_line(GraphObject& goLine, double x1, double x2, double y1, double y2, int nUnit)
{
	// first we need to make sure vline has no restriction for size change
	Tree tr;
	tr.Root.Dimension.Units.nVal = nUnit;
	//tr.Root.Dimension.Attachment.nVal = 1; // page
	tr.Root.Direction.nVal = LN_FREE; //
	Tree tr1;
	tr1 = goLine.GetFormat(FPB_OTHER, FOB_ALL, true, true);
	
	vector vy(2), vx(2);
	vx[0] = x1;
	vx[1] = x2;
	vy[0] = y1;
	vy[1] = y2;
	tr.Root.Data.X.dVals = vx;
	tr.Root.Data.Y.dVals = vy;

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

///Sandy add 2007-3-8
bool move_span_vline(GraphObject& go, double dX, int nAttach, int nUnit)
{
	go.Attach = nAttach;
	Tree tr;
	tr.Root.Dimension.Units.nVal = nUnit;
	tr.Root.Dimension.Attachment.nVal = nAttach;
	tr.Root.Direction.nVal = 2; // vertical
	tr.Root.Span.nVal = 1;
	Tree tr1;
	tr1 = go.GetFormat(FPB_OTHER, FOB_ALL, true, true);
	DWORD dwOldStats = tr1.Root.States.nVal;
	tr.Root.States.nVal = dwOldStats | GOC_NO_VMOVE|GOC_NO_RESIZE|GOC_NO_ROTATE|GOC_NO_SKEW|GOC_NO_EDIT|GOC_NO_BORDERSIZE;
	vector vx(2);
	vx[0] = vx[1] = dX;
	vector vy(2);
	vy[0] = 0.;
	vy[1] = 100.;
	tr.Root.Data.X.dVals = vx;
	tr.Root.Data.Y.dVals = vy;
	//int iRet = go.UpdateThemeIDs(tr.Root);
	////out_int("err = ", iRet);
	//go.ApplyFormat(tr, true, true);
	//return true;
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}
//end


bool move_span_vrect(GraphObject& go, double dLeft, double dRight, int nAttach , int nUnit)
{
	//go.Attach = nAttach;
	//set_unit(go,nUnit);
	
	///add by sandy to try another way to set rect position
	vector vx(4);
	vx[0] = dLeft, vx[1] = dRight; vx[2] = dRight; vx[3] = dLeft; 
	//_check_convert_pos(lay, vx, bPercent, nAttach, true);

	Tree tr;
	tr.Root.Dimension.Units.nVal = nUnit;
	tr.Root.Dimension.Attachment.nVal = nAttach;
	tr.Root.Direction.nVal = 2; // vertical
	tr.Root.Span.nVal = 1;
	//tr.Root.Dimension.Left.dVal = dLeft;
	//tr.Root.Dimension.Width.dVal = dRight - dLeft;
	///add by sandy to try another way to set rect position
	tr.Root.Data.X.dVals = vx;
	
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}

/// Iris 12/06/2006 v8.0519 UPDATE_MAT_XY_RANGE_BY_DRAG_RECT
bool set_unit(GraphObject& go, int nUnit)
{
	if(!go.IsValid())
		return false;
	
	Tree tr;
	tr.Root.Dimension.Units.nVal = nUnit;
	//go.UpdateThemeIDs(tr.Root);
	//go.ApplyFormat(tr, true, true);
	//return true;
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}

///---Sim 12-12-2006 IMPROVE_MOVE_FUNCTION
//bool rect_move(GraphObject& go, double dLeft, double dTop, int nUnit)
bool rect_move(GraphObject& go, double dLeft, double dTop, int nUnit, double dRight, double dBottom)
///---END IMPROVE_MOVE_FUNCTION
{
	if(!go)
		return false;	
	
	Tree tr;
	tr.Root.Dimension.Units.nVal = nUnit;
	if(UNITS_SCALE == nUnit)
	{
		tr.Root.Dimension.Attachment.nVal = 2; // Layer and Scale
	}
	
	tr.Root.Dimension.Left.dVal = dLeft;
	tr.Root.Dimension.Top.dVal = dTop;
	///---Sim 12-12-2006 IMPROVE_MOVE_FUNCTION
	if ( __NANUM != dRight )
		tr.Root.Dimension.Width.dVal = dRight - dLeft;
	if ( __NANUM != dBottom )
		tr.Root.Dimension.Height.dVal = dBottom - dTop;
	///---END IMPROVE_MOVE_FUNCTION
		
	
	//go.UpdateThemeIDs(tr.Root);
	//go.ApplyFormat(tr, true, true);
	//return true;
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}

bool rect_resize(GraphObject& go, double dWidth, double dHeight, int nUnit)
{
	if(!go)
		return false;	
	
	Tree tr;
	tr.Root.Dimension.Units.nVal = nUnit;
	if(UNITS_SCALE == nUnit)
	{
		tr.Root.Dimension.Attachment.nVal = 2; // Layer and Scale
	}
	///Sandy 2007-3-28 add default value -1(or any value less than 0) to means no change
	//tr.Root.Dimension.Width.dVal = dWidth;
	//tr.Root.Dimension.Height.dVal = dHeight;
	if(dWidth>=0)
		tr.Root.Dimension.Width.dVal = dWidth;
	if(dHeight>=0)
		tr.Root.Dimension.Height.dVal = dHeight;
	//
	//go.UpdateThemeIDs(tr.Root);
	//go.ApplyFormat(tr, true, true);
	//return true;
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
	
}


bool rect_get_position(GraphObject& go, double& dLeft, double& dTop, double& dRight, double& dBottom, int nUnit)
{
	if(!go.IsValid())
		return false;
	
	set_unit(go, nUnit);

	Tree tr;
	tr = go.GetFormat(FPB_ALL, FOB_ALL, true, true);
	
	dLeft = tr.Root.Dimension.Left.dVal;
	dRight = tr.Root.Dimension.Left.dVal + tr.Root.Dimension.Width.dVal;
	dTop = tr.Root.Dimension.Top.dVal;
	dBottom = tr.Root.Dimension.Top.dVal + tr.Root.Dimension.Height.dVal;
	
	return true;

}



bool rect_get_size(GraphObject& go, double& dWidth, double& dHeight, int nUnit)
{
	if(!go.IsValid())
		return false;
	///Sophy 6/12/2009 IMPROVE_RISETIME_TOOL_FOR_OSCILLOSCOPE_SIGNAL_PROCESSING will set in rect_get_position();
	//if( !set_unit(go, nUnit) )
		//return false;
	///end IMPROVE_RISETIME_TOOL_FOR_OSCILLOSCOPE_SIGNAL_PROCESSING
	
	double dLeft, dTop, dRight, dBottom;
	if( !rect_get_position(go, dLeft, dTop, dRight, dBottom, nUnit) )
		return false;
	
	dWidth = fabs(dRight - dLeft);
	dHeight = fabs(dTop - dBottom);		
	return true;
}
///end UPDATE_MAT_XY_RANGE_BY_DRAG_RECT

//--------- CPY 10/27/06 COLOR_SPECTRUM_PLOT
bool plot_color_spectrum(DataPlot& dp, GraphLayer& gl, const Worksheet& wks, int nX, int nY, int nC)
{
	DataRange dr;
	dr.Add(wks, nX, "X");
	dr.Add(wks, nY, "Y");
	int nPlot = gl.AddPlot(dr, IDM_PLOT_COLUMN);
	if(nPlot >= 0)
	{
		Dataset aa(wks, nX);
		Dataset bb(wks, nY);
		if(aa && bb)
		{
			gl.X.From = aa[0];
			gl.X.To = aa[aa.GetSize()-1];
			gl.Y.From = 0;
			gl.Y.To = bb[0];
		}
		Tree tr;
		int nRGBcol = nC - nY;// offset from Y
		tr.Root.Spacing.Gap.nVal = 0;
		tr.Root.Pattern.Border.Width.nVal = 0;
		tr.Root.Pattern.Fill.Pattern.PatternColor.nVal = INDEX_COLOR_AUTOMATIC;
		tr.Root.Pattern.Fill.FillColor.nVal = OCOLOR_COL_OFFSET_RGB(nRGBcol);
		dp = gl.DataPlots(nPlot);
		//dp.UpdateThemeIDs(tr.Root);
		//dp.ApplyFormat(tr, true, true);
		//return true;
		int nErr = dp.UpdateThemeIDs(tr.Root);
		if(nErr == 0)
		{
			dp.ApplyFormat(tr, true, true);
			return true;
		}
		out_int("err = ", nErr);
	}
	return false;
}
//--------- end 

/// AW 11/09/06 ADD_SCALER_OBJECT
// CPY 11/16/06, when bRoundScale, dScaleSize will be rounded to 1 significant digits actual value is updated to dScaleSize
//void add_y_scaler(GraphLayer &gl, string strUnits, int nUnit, double dLength, double dTop, double dUnitValue)// UNITS_LAYER(%Layer), 20.0(1/5 of layer height), 0 
bool add_y_scaler(GraphLayer &gl, GraphObject& go, double& dScaleSize, LPCSTR lpcszUnits, double dLeft, double dTop, bool bRoundScale, bool bEnumNextName)
{
	/// Hong 11/10/07 QA80-10671 FIX_PCLAMP_XY_SCALER_HAVE_DIFF_UNITS
	/*
	if( !gl )
		return false;
	// Since copy layer will copy all objects, so we have to remove Scaler object first.
	go = gl.GraphObjects("Scaler");
	if( !go )
		go = gl.CreateGraphObject(GROBJ_TN_SCALER);
	//------ CPY 7/13/07 QA70-9062 ADD_NEW_XYSCALE_OBJ
	else if(bEnumNextName)
	{
		int nn = 1;
		GraphObject gg;
		string strName;
		do {
			strName = "Scaler" + (nn++);
			gg = gl.GraphObjects(strName);
		}while(gg);
		go = gl.CreateGraphObject(GROBJ_TN_SCALER);
		go.SetName(strName);
	}
	//------
	
	if( !go )
		return false;
	
	TreeNode tr = go.GetFormat(FPB_ALL, FOB_ALL, true, true);

	// turn off X axis
	TreeNode trShow = tr.Root.Axes.X.GetNode("Show");
	trShow.nVal = 0;
	
	if(bRoundScale)
	{
		string str = ftoa(dScaleSize, "*1*"); // 1 significant digits
		dScaleSize = atof(str);
	}
		
	// Position scaler object
	tr.Root.Dimension.Attachment.nVal = 0;
	tr.Root.Dimension.Units.nVal = UNITS_LAYER; // % of layer for the pos itself
	tr.Root.Dimension.Left.dVal = dLeft;
	tr.Root.Dimension.Top.dVal = dTop; 
	
	// Update Y scaler axis
	tr.Root.Axes.Y.Dimension.Units.nVal = UNITS_SCALE;
	tr.Root.Axes.Y.Dimension.Position.nVal = SAP_Begin;
	tr.Root.Axes.Y.Dimension.Offset.dVal = 0.0;
	tr.Root.Axes.Y.Dimension.Length.dVal = dScaleSize;
	tr.Root.Axes.Y.Width.nVal = 1;
	
	// Update Y scaler axis title
	tr.Root.Axes.Y.Title.Angle.dVal = 0;
	tr.Root.Axes.Y.Title.Dimension.Units.nVal = UNITS_LAYER;
	tr.Root.Axes.Y.Title.Dimension.XOffset.dVal = 1; //1% of layer width
	tr.Root.Axes.Y.Title.Font.Size.nVal = 14;
	tr.Root.Axes.Y.Title.Alignment.Vertical.nVal = 1; // center
	tr.Root.Axes.Y.Title.Alignment.Horizontal.nVal = 0; // set left for Y axis
	TreeNode trText = tr.Root.Axes.Y.Title.GetNode("Text");
	string strUnits;
	strUnits.Format("%s %s", ftoa(dScaleSize), lpcszUnits); 
	trText.strVal = strUnits;
	
	
	// Arrow's begin and end style
	//tr.Root.Axes.Y.Arrow.Begin.Style.nVal = 2;
	//tr.Root.Axes.Y.Arrow.End.Style.nVal = 2;
	//tr.Root.KeepInside.nVal = 1;
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;
	*/
	double dXScaleSize = 1.0;
	string strXUnits = "X Scale";
	if ( add_xy_scaler(gl, go, dXScaleSize, dScaleSize, strXUnits, lpcszUnits, dLeft, dTop, bRoundScale, bEnumNextName) )
	{
		TreeNode tr = go.GetFormat(FPB_ALL, FOB_ALL, true, true);

		// turn off X axis
		TreeNode trShow = tr.Root.Axes.X.GetNode("Show");
		trShow.nVal = 0;
		
		int nErr = go.UpdateThemeIDs(tr.Root);
		if(nErr == 0)
		{
			go.ApplyFormat(tr, true, true);
			return true;
		}
	}
	/// end FIX_PCLAMP_XY_SCALER_HAVE_DIFF_UNITS
}
/// END ADD_SCALER_OBJECT

///---Sim 07-17-2007 ADD_XY_SCALER_OBJECT
bool add_xy_scaler(GraphLayer &gl, GraphObject& go, double& dXScaleSize, double& dYScaleSize, LPCSTR lpcszXUnits, LPCSTR lpcszYUnits, double dLeft, double dTop, bool bRoundScale, bool bEnumNextName)
{
	if( !gl )
		return false;
	// Since copy layer will copy all objects, so we have to remove Scaler object first.
	go = gl.GraphObjects("Scaler");
	if( !go )
		go = gl.CreateGraphObject(GROBJ_TN_SCALER);
	//------ CPY 7/13/07 QA70-9062 ADD_NEW_XYSCALE_OBJ
	else if(bEnumNextName)
	{
		int nn = 1;
		GraphObject gg;
		string strName;
		do {
			strName = "Scaler" + (nn++);
			gg = gl.GraphObjects(strName);
		}while(gg);
		go = gl.CreateGraphObject(GROBJ_TN_SCALER);
		go.SetName(strName);
	}
	//------
	
	if( !go )
		return false;
	
	TreeNode tr = go.GetFormat(FPB_ALL, FOB_ALL, true, true);

	if(bRoundScale)
	{
		string str;
		str = ftoa(dXScaleSize, "*1*"); // 1 significant digits
		dXScaleSize = atof(str);
		str = ftoa(dYScaleSize, "*1*"); // 1 significant digits
		dYScaleSize = atof(str);
	}
		
	// Position scaler object
	tr.Root.Dimension.Attachment.nVal = 0;
	tr.Root.Dimension.Units.nVal = UNITS_LAYER; // % of layer for the pos itself
	tr.Root.Dimension.Left.dVal = dLeft;
	tr.Root.Dimension.Top.dVal = dTop; 
	
	TreeNode trText;
	string strUnits;
	
	// Update X scaler axis
	tr.Root.Axes.X.Dimension.Units.nVal = UNITS_SCALE;
	tr.Root.Axes.X.Dimension.Position.nVal = SAP_Begin;
	tr.Root.Axes.X.Dimension.Offset.dVal = 0.0;
	tr.Root.Axes.X.Dimension.Length.dVal = dXScaleSize;
	tr.Root.Axes.X.Width.nVal = 1;
	
	// Update X scaler axis title
	tr.Root.Axes.X.Title.Angle.dVal = 0;
	tr.Root.Axes.X.Title.Dimension.Units.nVal = UNITS_LAYER;
	tr.Root.Axes.X.Title.Dimension.YOffset.dVal = 1; //1% of layer width
	tr.Root.Axes.X.Title.Font.Size.nVal = 14;
	tr.Root.Axes.X.Title.Alignment.Vertical.nVal = 0; // set bottom for X axis
	tr.Root.Axes.X.Title.Alignment.Horizontal.nVal = 1; // center
	trText = tr.Root.Axes.X.Title.GetNode("Text");
	strUnits.Format("%s %s", ftoa(dXScaleSize), lpcszXUnits); 
	trText.strVal = strUnits;
	
	// Update Y scaler axis
	tr.Root.Axes.Y.Dimension.Units.nVal = UNITS_SCALE;
	tr.Root.Axes.Y.Dimension.Position.nVal = SAP_Begin;
	tr.Root.Axes.Y.Dimension.Offset.dVal = 0.0;
	tr.Root.Axes.Y.Dimension.Length.dVal = dYScaleSize;
	tr.Root.Axes.Y.Width.nVal = 1;
	
	// Update Y scaler axis title
	tr.Root.Axes.Y.Title.Angle.dVal = 0;
	tr.Root.Axes.Y.Title.Dimension.Units.nVal = UNITS_LAYER;
	tr.Root.Axes.Y.Title.Dimension.XOffset.dVal = -1; //1% of layer width
	tr.Root.Axes.Y.Title.Font.Size.nVal = 14;
	tr.Root.Axes.Y.Title.Alignment.Vertical.nVal = 1; // center
	tr.Root.Axes.Y.Title.Alignment.Horizontal.nVal = 2; // set left for Y axis
	trText = tr.Root.Axes.Y.Title.GetNode("Text");
	strUnits.Format("%s %s", ftoa(dYScaleSize), lpcszYUnits); 
	trText.strVal = strUnits;
	
	
	// Arrow's begin and end style
	//tr.Root.Axes.X.Arrow.Begin.Style.nVal = 2;
	//tr.Root.Axes.X.Arrow.End.Style.nVal = 2;
	//tr.Root.Axes.Y.Arrow.Begin.Style.nVal = 2;
	//tr.Root.Axes.Y.Arrow.End.Style.nVal = 2;
	//tr.Root.KeepInside.nVal = 1;
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;
}
///---END ADD_XY_SCALER_OBJECT

///Sandy 2006-12-6 add
/// Cloud 11/30/07 COORDINATE_SHOULD_BE_DOUBLE
//bool add_ellipse(const Layer& lay, GraphObject& go, int x0, int y0, int x1, int y1, int nFillColor, int nAttach, bool bPercent) 
bool add_ellipse(const Layer& lay, GraphObject& go, double x0, double y0, double x1, double y1, int nFillColor, int nAttach, bool bPercent)
/// End COORDINATE_SHOULD_BE_DOUBLE
{
	if(!lay.IsValid())
		return false;
	go = lay.CreateGraphObject(GROT_ELLIPSE);
	go.Attach = nAttach;
	vector vx(4), vy(4);

	vx[0] = x0, vx[1] = x1; vx[2] = x1; vx[3] = x0;
	vy[0] = y0, vy[1] = y0; vy[2] = y1; vy[3] = y1;
	_check_convert_pos(lay, vx, bPercent, nAttach, true);
	_check_convert_pos(lay, vy, bPercent, nAttach, false);

	Tree tr;
	tr = go.GetFormat(FPB_DATA, FOB_ALL, true, true);
	//tr.Root.Direction.nVal = nDirection;
	//tr.Root.Span.nVal = bSpan?1:0;
	tr.Root.Data.X.dVals = vx;
	tr.Root.Data.Y.dVals = vy;
	tr.Root.Fill.Color.nVal = nFillColor; 
	
	//go.UpdateThemeIDs(tr.Root);
	//go.ApplyFormat(tr, true, true);
	//return true;
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}

///Sophy 3/4/2010 EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL
bool add_circle(const Layer& layer, GraphObject& go, double xc, double yc, double rx, double ry, int nFillColor, int nBorderColor, int nAttach, bool bPercent)
{
	double x0 = xc - rx, x1 = xc + rx, y0 = yc - ry, y1 = yc + ry;
	if ( add_ellipse(layer, go, x0, y0, x1, y1, nFillColor, nAttach, bPercent) )
	{
		go.Height = go.Width;
		Tree tr;
		tr = go.GetFormat(FPB_ALL, FOB_ALL, true, true);
		tr.Root.Border.Color.nVal = nBorderColor;
		tr.Root.Border.Width.nVal = 1;
		tr.Root.States.nVal = GOC_NO_ROTATE | GOC_NO_SKEW | GOC_NO_EDIT | GOC_NO_BORDERSIZE | GOC_NO_IN_PLACE_EDIT;	
		int nErr = go.UpdateThemeIDs(tr.Root);
		if(nErr == 0)
		{
			go.ApplyFormat(tr, true, true);
			return true;
		}
	}
	return false;
}

///end EXTEND_ROI_SHAPE_FOR_CLUSTER_TOOL

bool remove_GraphObjects_with_prefix(Layer& lay, LPCSTR lpcstrPrefix)
{
	if(!lay.IsValid())
		return false;
	///Sandy 2007-28-change to use LTScript
	//foreach(GraphObject go in lay.GraphObjects)
	//{
		//string str = go.GetName();
		//if(0 == strncmp(str, lpcstrPrefix, strlen(lpcstrPrefix)))
			//go.Destroy();
	//}
	string strPerfix = lpcstrPrefix;
	string strLT = "label -r " + strPerfix + "*;";
	lay.LT_execute(strLT);
	return true;
	//end
}
///end

/// Iris 12/18/2006 v8.0527 XYZ2MAT_DISABLE_RECT_MOVEMENT_EXCEPT_TPS_METHOD
bool go_is_moveable(GraphObject& go, bool bCheckVertical)
{
	Tree tr;
	tr = go.GetFormat(FPB_OTHER, FOB_ALL, true, true);
	DWORD 	dwStats = tr.Root.States.nVal;
	DWORD 	dwCheck = bCheckVertical? GOC_NO_VMOVE : GOC_NO_HMOVE;
	if(dwStats & dwCheck > 0)
		return false;
	return true;
}

bool go_is_resized(GraphObject& go)
{
	Tree tr;
	tr = go.GetFormat(FPB_OTHER, FOB_ALL, true, true);
	DWORD dwStats = tr.Root.States.nVal;
	if(dwStats & GOC_NO_RESIZE > 0)
		return false;
	return true;	
}
///end XYZ2MAT_DISABLE_RECT_MOVEMENT_EXCEPT_TPS_METHOD


///Sandy 2006-12-26 add 
bool get_go_size(GraphObject& go, double* pw, double* ph)
{
	if(!go.IsValid())
		return false;

	double dd1, dd2;
	
	Tree tr;
	tr = go.GetFormat(FPB_DATA, FOB_ALL, true, true);
	vector vx, vy;
	vx = tr.Root.Data.X.dVals;
	vy = tr.Root.Data.Y.dVals;
	
	double dMax, dMin;
	vx.GetMinMax(dMin, dMax);

	double dWidth = dMax - dMin;
	
	vy.GetMinMax(dMin, dMax);	
	
	double dHeight = dMax - dMin;
	

	if(pw!=NULL)
		*pw = dWidth;
	if(ph!=NULL)
		*ph = dHeight;
	return true;

}



////////////////////////////////////////////////////////
// CPY Roman 1/5/07 OGS_BASED_AXIS_SCROLLER_RECT
////////////////////////////////////////////////////////
bool get_go_rect(GraphObject& go, FRECT& fr)
{
	if(!go.IsValid())
		return false;
	
	Tree tr;
	tr = go.GetFormat(FPB_DATA, FOB_ALL, true, true);
	vector vx, vy;
	vx = tr.Root.Data.X.dVals;
	vy = tr.Root.Data.Y.dVals;
	if(vx.GetSize() < 3)
		return false;
	fr.left = vx[0];
	fr.top = vy[0];
	fr.right = vx[2];
	fr.bottom = vy[2];
	return true;
}

///Sandy 2007-3-12 add
bool span_rect(GraphObject& go,int nDirection, bool bSpan) 
{
	if(!go.IsValid())
		return false;

	Tree tr;
	tr = go.GetFormat(FPB_DATA, FOB_ALL, true, true);
	tr.Root.Direction.nVal = nDirection;
	tr.Root.Span.nVal = bSpan?1:0;
	
	//go.UpdateThemeIDs(tr.Root);
	//go.ApplyFormat(tr, true, true);
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	

}

///Sandy 2007-3-12 add
bool fill_rect_with_color( GraphObject& go,  int nFillColor) 
{
	if(!go.IsValid())
		return false;

	Tree tr;
	tr = go.GetFormat(FPB_DATA, FOB_ALL, true, true);
	tr.Root.Fill.Color.nVal = nFillColor; 
	
	//go.UpdateThemeIDs(tr.Root);
	//go.ApplyFormat(tr, true, true);
	//return true;
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}

///sandy 2007-3-28 add
bool add_label(Layer& ll, GraphObject& grText, double x, double y, LPCSTR lpcszText)
{
	if(!ll)
		return false;

	//add_text(ll, grText, 50, 50, lpcszText, 16, false);
	add_text(ll, grText, 50, 50, lpcszText, 16,  false, ATTACH_TO_SCALE);
	set_text_border(grText, GTB_LINE);
	grText.X = x;
	grText.Y = y;

	return true;
}
///sandy 2007-3-29
bool go_is_span_in_dir(GraphObject& go, bool& bSpan, int& nDir)
{
	if(!go.IsValid())
		return false;

	Tree tr;
	tr = go.GetFormat(FPB_DATA, FOB_ALL, true, true);
	if(nDir && tr.Root.Direction)
		nDir = tr.Root.Direction.nVal;
	if(tr.Root.Span)
		bSpan = tr.Root.Span.nVal;
	else
		return false;
	
	return true;
	
}

bool get_go_pattern_color(GraphObject& go, int& nPatternColor)
{
	if(!go.IsValid())
		return false;
	
	Tree tr;
	tr = go.GetFormat(FPB_ALL, FOB_ALL, true, true);
	if(tr.Root.Fill.Pattern.PatternColor)
		nPatternColor = tr.Root.Fill.Pattern.PatternColor.nVal;
	else
		return false;
	
	return true;
}

bool get_go_LTScript_event(GraphObject& go, string& strLTScript, int& nEvent)
{
	if(!go.IsValid())
		return false;
	
	Tree tr;
	tr = go.GetFormat(FPB_ALL, FOB_ALL, true, true);
	
	if(nEvent&&tr.Root.Event)
		nEvent = tr.Root.Event.nVal;
	
	if(!tr.Root.Script)
		return false;
	
	strLTScript = tr.Root.Script.strVal;
	
	return true;	
}
///sandy 2007-3-29 end

///sandy add 2007-4-2 
bool set_go_selectable(GraphObject& go, bool bEnable)
{
	Tree tr;
	tr = go.GetFormat(FPB_OTHER, FOB_ALL, true, true);
	DWORD dwOldStats = tr.Root.States.nVal;
	
	
	DWORD dwBits = dwOldStats;
	if(!bEnable)
	{
		dwBits = dwOldStats|GOC_NO_SELECT;
	}
	else
	{
		dwBits = dwOldStats & (~GOC_NO_SELECT);		
	}
	
	tr.Root.States.nVal = dwBits;
	//go.UpdateThemeIDs(tr.Root);
	//go.ApplyFormat(tr, true, true);
	//return true;	
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}

/// Hong 04/23/07 v8.0606 ALLOW_USER_DELETE_LINE_CONTROL
bool set_go_user_deleteable(GraphObject& go, bool bEnable)
{
	Tree tr;
	tr = go.GetFormat(FPB_OTHER, FOB_ALL, true, true);
	DWORD dwOldStats = tr.Root.States.nVal;
	
	
	DWORD dwBits = dwOldStats;
	if(bEnable)
	{
		dwBits = dwOldStats|GOC_REV_USER_DEL;
	}
	else
	{
		dwBits = dwOldStats & (~GOC_REV_USER_DEL);		
	}
	
	tr.Root.States.nVal = dwBits;
	//go.UpdateThemeIDs(tr.Root);
	//go.ApplyFormat(tr, true, true);
	//return true;	
	int nErr = go.UpdateThemeIDs(tr.Root);
	if(nErr == 0)
	{
		go.ApplyFormat(tr, true, true);
		return true;
	}
	out_int("err = ", nErr);
	return false;	
}
/// end ALLOW_USER_DELETE_LINE_CONTROL

//////////////////////////////////////////////////////////////////////////////
///Sandy 2007-3-12 ///////move from ocimgROIPreview.h for ROI Object saving///
//////////////////////////////////////////////////////////////////////////////
///Sandy 2008-3-17 later need to remove dataid since it isn't a good solution
bool make_anchors_tree_without_info(TreeNode& tr, int nAnchorsNum)
{
	
	if(!tr.IsValid())
		return false;
	
	for(int ii = 0; ii<nAnchorsNum;ii++)
	{
		TreeNode trAnchor;
		int nID = IDE_ANCHOR_ID + ii + 1;
		tree_check_get_node_by_dataid(tr, trAnchor, "Anchor"+(string)(ii+1), nID);
		//TreeNode trAnchor = tree_check_get_node(tr, "Anchor"+(string)(ii+1));
		
		TreeNode trAnchorName, trAnchorType, trAnchorX, trAnchorY, trAnchorW, trAnchorH;
		tree_check_get_node_by_dataid(trAnchor, trAnchorName, "Name", nID+IDE_ATTR_BIT_ANCHOR_NAME);
		tree_check_get_node_by_dataid(trAnchor, trAnchorType, "Type", nID+IDE_ATTR_BIT_ANCHOR_TYPE);
		tree_check_get_node_by_dataid(trAnchor, trAnchorX, "X", nID+IDE_ATTR_BIT_ANCHOR_X);
		tree_check_get_node_by_dataid(trAnchor, trAnchorY, "Y", nID+IDE_ATTR_BIT_ANCHOR_Y);
		tree_check_get_node_by_dataid(trAnchor, trAnchorW, "Width", nID+IDE_ATTR_BIT_ANCHOR_W);
		tree_check_get_node_by_dataid(trAnchor, trAnchorH, "Height", nID+IDE_ATTR_BIT_ANCHOR_H);
		
		//TreeNode trAnchorName = tree_check_get_node(trAnchor, "Name");
		//TreeNode trAnchorType = tree_check_get_node(trAnchor, "Type");
		//TreeNode trAnchorX = tree_check_get_node(trAnchor, "X");
		//TreeNode trAnchorY = tree_check_get_node(trAnchor, "Y");
		//TreeNode trAnchorW = tree_check_get_node(trAnchor, "Width"); 
		//TreeNode trAnchorH = tree_check_get_node(trAnchor, "Height");

	}
	
	TreeNode trNum ;//= tree_check_get_node(tr, "Number");
	tree_check_get_node_by_dataid(tr, trNum,"Number", IDE_ANCHOR_NUMBER);
	
	return true;	

}
//#include <..\originlab\ImgChannelData.h>


bool get_anchor_xy_from_tree(TreeNode& trAnchors, int nIndex,  double& x0, double& y0, double& w, double& h)
{
	if(!trAnchors.IsValid()||nIndex<=0)
		return false;
	
	TreeNode trNum = tree_find_node_by_dataID(trAnchors, IDE_ANCHOR_NUMBER);
	if(!trNum.IsValid() || trNum.nVal == 0 || nIndex > trNum.nVal)
		return false;

	int nID = IDE_ANCHOR_ID + nIndex;
	TreeNode trAnchor = tree_find_node_by_dataID(trAnchors, nID);
	if(!trAnchor.IsValid())
		return false;
	
	TreeNode trAnchorName = tree_find_node_by_dataID(trAnchor, nID+IDE_ATTR_BIT_ANCHOR_NAME);
	TreeNode trAnchorType = tree_find_node_by_dataID(trAnchor, nID+IDE_ATTR_BIT_ANCHOR_TYPE);
	TreeNode trAnchorX = tree_find_node_by_dataID(trAnchor, nID+IDE_ATTR_BIT_ANCHOR_X);
	TreeNode trAnchorY = tree_find_node_by_dataID(trAnchor, nID+IDE_ATTR_BIT_ANCHOR_Y);
	TreeNode trAnchorW = tree_find_node_by_dataID(trAnchor, nID+IDE_ATTR_BIT_ANCHOR_W);
	TreeNode trAnchorH = tree_find_node_by_dataID(trAnchor, nID+IDE_ATTR_BIT_ANCHOR_H);
	
	if(!trAnchorName.IsValid()||!trAnchorType.IsValid()||!trAnchorX.IsValid()
		||!trAnchorY.IsValid()||!trAnchorW.IsValid()||!trAnchorH.IsValid())
	{
		return false;
	}
	
	w = trAnchorW.dVal;
	h = trAnchorH.dVal;
	x0 = trAnchorX.dVal;
	y0 = trAnchorY.dVal;
	
	return true;	
	
}

bool update_tree_anchors_object_type(int nObjectType, TreeNode& trAnchors)
{
	if(!trAnchors.IsValid())
		return false;
	
	TreeNode trNum = tree_find_node_by_dataID(trAnchors, IDE_ANCHOR_NUMBER);
	if(!trNum.IsValid())
		return false;
	int nNumAnchors = trNum.nVal;
	
	for(int ii = 1; ii<=nNumAnchors; ii++)
	{
		TreeNode& trAnchor = trAnchors.GetNode("Anchor"+(string)ii);
		if(!trAnchor.IsValid())
			return false;	
		
		TreeNode& trAnchorType = trAnchor.GetNode("Type");
		if(!trAnchorType.IsValid() || trAnchorType.nVal ==  nObjectType)
			return false;
		
		
		trAnchorType.nVal = nObjectType;
	}
	return true;
}

bool save_anchors_to_tree(Layer& lay, TreeNode& tr, LPCSTR lpcstrPrefix)
{
	///Sandy 2007-3-12 add remove all treenode in the tr
	//tr.RemoveChildrenWithPrefix("");
	
	if(!lay.IsValid()||!tr.IsValid())
		return false;
	
	int nNumAnchors = 0;
	/// Hong 12/26/08 v8.0991 IMPROVE_SPEED
	/*
	foreach(GraphObject go in lay.GraphObjects)
	{
		string str = go.GetName();
		if(0 == strncmp(str, lpcstrPrefix, strlen(lpcstrPrefix)))
		{
	*/
	Collection<GraphObject>			goColl;
	if ( lay.GetSpecialGraphicObjectsCollection(goColl, lpcstrPrefix) )
	{
		foreach ( GraphObject go in goColl )
		{
			string str = go.GetName();
	/// end IMPROVE_SPEED
			nNumAnchors++;
			TreeNode trAnchor;
			int nID = IDE_ANCHOR_ID + nNumAnchors;
			tree_check_get_node_by_dataid(tr, trAnchor, "Anchor"+(string)(nNumAnchors), nID);
			
			TreeNode trAnchorName, trAnchorType, trAnchorX, trAnchorY, trAnchorW, trAnchorH;
			tree_check_get_node_by_dataid(trAnchor, trAnchorName, "Name", nID+IDE_ATTR_BIT_ANCHOR_NAME);
			tree_check_get_node_by_dataid(trAnchor, trAnchorType, "Type", nID+IDE_ATTR_BIT_ANCHOR_TYPE);
			tree_check_get_node_by_dataid(trAnchor, trAnchorX, "X", nID+IDE_ATTR_BIT_ANCHOR_X);
			tree_check_get_node_by_dataid(trAnchor, trAnchorY, "Y", nID+IDE_ATTR_BIT_ANCHOR_Y);
			tree_check_get_node_by_dataid(trAnchor, trAnchorW, "Width", nID+IDE_ATTR_BIT_ANCHOR_W);
			tree_check_get_node_by_dataid(trAnchor, trAnchorH, "Height", nID+IDE_ATTR_BIT_ANCHOR_H);
			
			trAnchorName.strVal = str;
			int nType;
			go.GetObjectType(&nType);
			trAnchorType.nVal = nType;
			
			///Sandy 2007-5-5 improve the rect size 
			/////Sandy 2007-3-13 
			//trAnchorX.dVal = go.X;
			//trAnchorY.dVal = go.Y;
			//double dw, dh;
			//get_go_size(go, &dw, &dh);
			//trAnchorW.dVal = dw;
			//trAnchorH.dVal = dh;			

			
			FRECT 	frThumb;
			if( !go.GetTempBoundingBox(&frThumb) )
				return false;	
				
			trAnchorX.dVal =	(frThumb.left +  frThumb.right)/2.0;
			trAnchorY.dVal =	(frThumb.top + frThumb.bottom)/2.0;
			trAnchorW.dVal = ( frThumb.right - frThumb.left);
			trAnchorH.dVal = (frThumb.bottom - frThumb.top );
			//end 2007-5-5 
			
		}
	}
	
	TreeNode trNum;
	tree_check_get_node_by_dataid(tr, trNum,"Number", IDE_ANCHOR_NUMBER);
	trNum.nVal = nNumAnchors;
	
	return true;	

}


bool read_and_create_anchors_from_tree(Layer& lay, TreeNode& tr, LPCSTR lpcstrPrefix, GraphObject& go)
{

	if(!lay.IsValid()||!tr.IsValid())
		return false;
		
	TreeNode trNum = tree_find_node_by_dataID(tr, IDE_ANCHOR_NUMBER);
	if(!trNum.IsValid() || trNum.nVal == 0)
		return false;
	
	int nNumAnchors = trNum.nVal;
	
	for(int ii = 1; ii<=nNumAnchors; ii++)
	{
		int nID = IDE_ANCHOR_ID + ii;
		TreeNode trAnchor = tree_find_node_by_dataID(tr, nID);
		if(!trAnchor.IsValid())
			return false;
		
		TreeNode trAnchorName = tree_find_node_by_dataID(trAnchor, nID+IDE_ATTR_BIT_ANCHOR_NAME);
		TreeNode trAnchorType = tree_find_node_by_dataID(trAnchor, nID+IDE_ATTR_BIT_ANCHOR_TYPE);
		TreeNode trAnchorX = tree_find_node_by_dataID(trAnchor, nID+IDE_ATTR_BIT_ANCHOR_X);
		TreeNode trAnchorY = tree_find_node_by_dataID(trAnchor, nID+IDE_ATTR_BIT_ANCHOR_Y);
		TreeNode trAnchorW = tree_find_node_by_dataID(trAnchor, nID+IDE_ATTR_BIT_ANCHOR_W);
		TreeNode trAnchorH = tree_find_node_by_dataID(trAnchor, nID+IDE_ATTR_BIT_ANCHOR_H);
		
		if(!trAnchorName.IsValid()||!trAnchorType.IsValid()||!trAnchorX.IsValid()
			||!trAnchorY.IsValid()||!trAnchorW.IsValid()||!trAnchorH.IsValid())
		{
			return false;
		}
		
		///Sandy 2007-3-23 CHANGE_RECT_POSITION_VALUE_AS_DOUBLE
		//int nHalfW = trAnchorW.dVal/2;
		//int nHalfH = trAnchorH.dVal/2;
		//int nX = trAnchorX.dVal;
		//int nY = trAnchorY.dVal;
		double dHalfW = trAnchorW.dVal/2;
		double dHalfH = trAnchorH.dVal/2;
		double dX = trAnchorX.dVal;
		double dY = trAnchorY.dVal;
		
		GraphObject goTemp;
		if(trAnchorType.nVal == GROT_ELLIPSE)
		{
			//if( !add_ellipse(lay, goTemp, nX-nHalfW, nY-nHalfH, nX+nHalfW, nY+nHalfH, INDEX_COLOR_TRANSPARENT,  ATTACH_TO_SCALE,  false) )
			if( !add_ellipse(lay, goTemp, dX-dHalfW, dY-dHalfH, dX+dHalfW, dY+dHalfH, INDEX_COLOR_TRANSPARENT,  ATTACH_TO_SCALE,  false) )
				return false;			
		}
		else if(trAnchorType.nVal == GROT_RECT)
		{
			//if( !add_rect(lay, goTemp, nX-nHalfW, nY-nHalfH, nX+nHalfW, nY+nHalfH, INDEX_COLOR_TRANSPARENT,  ATTACH_TO_SCALE, LN_FREE, false,  false) )
			if( !add_rect(lay, goTemp, dX-dHalfW, dY-dHalfH, dX+dHalfW, dY+dHalfH, INDEX_COLOR_TRANSPARENT,  ATTACH_TO_SCALE, LN_FREE, false,  false) )
				return false;			
		}
		
		goTemp.SetName(trAnchorName.strVal);
		if(go != NULL)
			go = goTemp;
		
		//set_go_border_color(go, SYSCOLOR_GREEN);
		//set_LT_script(go, "events_from_img2xyz_go;" , GRCT_SIZEMOVE);	
		
	}
	return true;
}


///Sophy 8/26/2009 QA80-14169 MAKE_GRAPHOBJECT_FOR_PROGRAMMING_CONTROL_PRINTABLE
bool set_go_printable(GraphObject& go)
{
	if ( !go )
		return false;
	
	Tree trFormat;
	trFormat = go.GetFormat(FPB_ALL, FOB_ALL, true, true);
	trFormat.Root.States.nVal |= GOC_EXPORT_PROGRAMMED;
	
	if ( !go.ApplyFormat(trFormat, true, true) )
		return false;
	
	return true;
}
///end MAKE_GRAPHOBJECT_FOR_PROGRAMMING_CONTROL_PRINTABLE
//////////////////////////////end of ROI Object saving//////////////////////////////

//Sandy 2009-2-25 move from XF
double  get_radius(GraphObject& go, int nRadiusUnit, double& vertical_r2)
{
	double dWidth, dHeight;
	if(!rect_get_size( go, dWidth, dHeight, nRadiusUnit))
		return NANUM;
	
	if( vertical_r2 !=NULL)
		vertical_r2 = dHeight/2;
	
	return dWidth/2;
		
}


//Sandy 2009-2-25 move from XF
bool ellipse_move(GraphObject& go, double xc, double yc,  int nUnit )
{
	double r2;
	double r = get_radius(go, nUnit, r2);
	if(!rect_move(go, xc - r, yc + r2, nUnit, xc + r, yc - r2))
		return false;
	
	return true;
}

///Sophy 12/30/2009 QA80-14904-S1 SUPPORT_FLEXIBLE_ATTACHED_GROBJ_FOR_ROI_TOOLS
//bool get_attachment(GraphObject& grTarget, GraphObject& gr, int nPosition, int nObjType, DWORD dwCtrl)
//{
	//if( !grTarget || nObjType > GROBJ_TN_SCALER )
		//return false;
//
	//vector<string>	vsAttObjNames;
	//vector<int>		vnPositions;
	//vector<DWORD>	vnCtrls;
	//Tree trInfo;
	//if ( tree_get_binary_storage(trInfo, grTarget, ATTACHED_GRAPH_OBJECTS_INFO) && trInfo.attObjNames )
	//{
		//vsAttObjNames = trInfo.attObjNames.strVals;
		//vnPositions = trInfo.attObjPositions.nVals;
		//vnCtrls = trInfo.attObjPosCtrls.nVals;
	//}
	//vector<uint> vnIndices;
	//vnPositions.Find(vnIndices, nPosition);
	//for ( int ii = 0; ii < vnIndices.GetSize(); ii++ )
	//{
		//int nTargetIndex = vnIndices[ii];
		//if ( dwCtrl == vnCtrls[nTargetIndex] )
		//{
			//GraphLayer gl;
			//grTarget.GetParent(gl);
			//gr = gl.GraphObjects(vsAttObjNames[nTargetIndex]);
			//if ( gr.IsValid() )
				//return true;
		//}
	//}
	//
	//return false;
//}
//
//bool check_create_attachment(GraphObject& grTarget, GraphObject& gr, LPCSTR lpcszLabel, int nObjType, int nPosition, DWORD dwCtrl)
//{
	//if ( !grTarget || nPosition >= CTP_SIZE || nPosition < 0 )
		//return false;
//
	//vector<string>		vsAttachObjNames;
	//vector<int>			vnPositions;
	//vector<DWORD>		vnCtrls;
	//Tree trInfo;
	//if ( tree_get_binary_storage(trInfo, grTarget, ATTACHED_GRAPH_OBJECTS_INFO) && trInfo.attObjNames )
	//{
		//vsAttachObjNames = trInfo.attObjNames.strVals;
		//vnPositions = trInfo.attObjPositions.nVals;
		//vnCtrls = trInfo.attObjPosCtrls.nVals
	//}
//
	//if ( !get_attachment(grTarget, gr, nPosition, nObjType, dwCtrl) )
	//{
		//GraphLayer gl;
		//grTarget.GetParent(gl);
		//gr = gl.CreateGraphObject(nObjType);
		//if ( GROBJ_TN_TEXT == nObjType )
		//{
			//gr.Text = lpcszLabel;
			//Tree trFormat;
		 	//trFormat.Root.Font.Size.nVal = 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(nPosition == CTP_TOP || CTP_BOTTOM == nPosition)
		 		//trFormat.Root.Alignment.Horizontal.nVal = 1;// center
//
			//gr.UpdateThemeIDs(trFormat.Root);
			//gr.ApplyFormat(trFormat, true, true);	
		//}
		//vsAttachObjNames.Add(gr.GetName());
		//vnPositions.Add(nPosition);
		//vnCtrls.Add(dwCtrl);
	//}
	//connect_justify(grTarget, gr, nPosition, dwCtrl);
	//
	//trInfo.attObjNames.strVals = vsAttachObjNames;
	//trInfo.attObjPositions.nVals = vnPositions;
	//trInfo.attObjPosCtrls.nVals = vnCtrls;
	//
	//tree_put_binary_storage(trInfo, grTarget, ATTACHED_GRAPH_OBJECTS_INFO);
	//
	//return true;
//}
//
//void graphobjtool_events(GraphObjTool& iTool, int nEvent, int nMsg)
//{
	//if ( nMsg != 0 || OE_RESIZE == nEvent )
		//iTool.CheckAttachObjs();
	//iTool.OnEvent(nEvent, nMsg);
//}

///end SUPPORT_FLEXIBLE_ATTACHED_GROBJ_FOR_ROI_TOOLS

///Sophy 2/4/2010 PROPERLY_UPDATE_GROBJ_POSITION_ACCORDING_TO_LAYER_SCALE
double	update_position_by_scale(GraphLayer& glSrc, double dVal, bool bX/* = true*/)
{
	double dRet = dVal;
	int nScaleType;
	if ( get_scale_type(glSrc, nScaleType, bX) )
	{
		dRet = real_space(dVal, nScaleType);
	}
	return dRet;
}
///end PROPERLY_UPDATE_GROBJ_POSITION_ACCORDING_TO_LAYER_SCALE



//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////member functons of ShapeControl///////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool ShapeControl::createFromMainObj(GraphObject & goOriginal)
{
	if(!goOriginal)
		return false;
	m_goMain = goOriginal;
	
	string strName = m_goMain.GetName();
	m_strBaseName = strName.GetToken(0,'_');
	string ss = strName.GetToken(1,'_');
	
	m_nIndex = atoi(ss);
	vector<uint> vnUIDs;
	if(m_goMain.GetConnectedObjects(vnUIDs) > 0)
	{
		for(int ii = 0; ii< vnUIDs.GetSize(); ii++)
		{
			GraphObject go;
			go = Project.GetObject(vnUIDs[ii]);
			//if(go.GetName() == (strName +"_VCLine"))
			//{
				//m_goVCLine = go;
			//}
			if(go.GetName() ==  (strName +"_Title"))
			{
				m_goTitle = go;
			}
			if(go.GetName() ==  (strName +"_Label"))
			{
				m_goLabel = go;
			}				
		}

	}	
	
	//find no connect obj, such as the Line locking to a postion
	/// Hong 12/26/08 v8.0991 IMPROVE_SPEED
	//foreach(GraphObject go in m_layParent.GraphObjects)
	Collection<GraphObject>		goLines;
	m_layParent.GetSpecialGraphicObjectsCollection(goLines, strName +"_Line");
	foreach(GraphObject go in goLines)
	/// end IMPROVE_SPEED
	{
		if(go.GetName() == (strName +"_Line"))
		{
			m_goLine = go;
		}
		
		/////sandy 2007-4-18 add horizontal line
		//if(go.GetName() == (strName +"_HorizLine"))
		//{
			//m_goHLine = go;
		//}		
	}
	
	
	
	return true;
}

void ShapeControl::GetOptionalSettings(TreeNode& trOptionalSettings)
{
	bool bSpan; 	
	int nDir;
	if(go_is_span_in_dir(m_goMain, bSpan, nDir))
	{
		trOptionalSettings.Span.nVal = bSpan;
		trOptionalSettings.Dir.nVal = nDir;
	}
	else
	{
		trOptionalSettings.Span.nVal = true;
		trOptionalSettings.Dir.nVal = LN_VERTICAL;		
	}
	

	if(m_goTitle.IsValid())
		trOptionalSettings.Title.strVal = m_goTitle.Text;
	else
		trOptionalSettings.Title.strVal = "";
	
	int nPatternColor;
	if(get_go_pattern_color(m_goMain, nPatternColor))
		trOptionalSettings.Color.nVal = nPatternColor;
	else
		trOptionalSettings.Color.nVal = 6;
	
	string strLTScript; 
	int nEventID;	
	if(get_go_LTScript_event(m_goMain, strLTScript, nEventID))
	{
		trOptionalSettings.LTScript.strVal = strLTScript;
		trOptionalSettings.EventID.nVal = nEventID;
	}
	else
	{
		trOptionalSettings.LTScript.strVal = "";
		trOptionalSettings.EventID.nVal = GRCT_ANY_EVENT;		
	}
}

void ShapeControl::Remove()
{
	string strName = m_strBaseName + "_"+(string)(m_nIndex);
	remove_GraphObjects_with_prefix(m_layParent, strName);
	//string strLT = "label -r " + strName + ";";
	//LT_execute(strLT);	
}

/// Fisher 9/16/2008 GRAPH_OBJ_CURVE_TOOL
//bool ShapeControl::Create(Layer& lay, LPCSTR lpcszNameBase, int nIndex, TreeNode& trSettings, int nMainObj, BOOL bLine, BOOL bTitle, BOOL bLabel)//, BOOL bHorizLine)
bool ShapeControl::Create(Layer& lay, LPCSTR lpcszNameBase, int nIndex, TreeNode& trSettings, int nMainObj, BOOL bLine, BOOL bTitle, BOOL bLabel, int nAttach)//, BOOL bHorizLine)
/// end GRAPH_OBJ_CURVE_TOOL
{
	//if(!lay.IsValid()||!trSettings||!trSettings.X||!trSettings.Y||!trSettings.Width||!trSettings.Height)
	if(!lay.IsValid()||!trSettings||!trSettings.X||!trSettings.Y||!trSettings.Left||!trSettings.Right)
		return false;
	
	//clean up if the name exist
	m_nIndex = nIndex;
	m_strBaseName = lpcszNameBase;
	m_layParent = lay;
	Remove();
	
	///////////////////////////////////////////////
	////////read settings tree to get special info
	//read initialize info from setting tree node
	double dX = trSettings.X.dVal;
	double dY = trSettings.Y.dVal;
	//double dHalfW = trSettings.Width.dVal/2;
	//double dHalfH = trSettings.Height.dVal/2;
	double dLeft = trSettings.Left.dVal;
	double dRight = trSettings.Right.dVal;
	double dLineX = (trSettings.LineX ? trSettings.LineX.dVal : dX);
	
	double dTop = (trSettings.Top ? trSettings.Top.dVal : dY);
	double dBottom = (trSettings.Bottom ? trSettings.Bottom.dVal : dY);
	
	//optional setting
	bool bSpan = (trSettings.OptionalSettings.Span ? trSettings.OptionalSettings.Span.nVal : true);
	int nDir = (trSettings.OptionalSettings.Dir ? trSettings.OptionalSettings.Dir.nVal : LN_VERTICAL);
	bool bBehindData =  (trSettings.OptionalSettings.BehindData ? trSettings.OptionalSettings.BehindData.nVal : false);

	string strTitle = (trSettings.OptionalSettings.Title ? trSettings.OptionalSettings.Title.strVal : lpcszNameBase);
	int nPatternColor = (trSettings.OptionalSettings.Color ? trSettings.OptionalSettings.Color.nVal : 6);
	int nBorderColor = (trSettings.OptionalSettings.BorderColor ? trSettings.OptionalSettings.BorderColor.nVal : 6);
	int nPatternStyle = (trSettings.OptionalSettings.PatternStyle ? trSettings.OptionalSettings.PatternStyle.nVal : 0);
	double nBorderWidth = (trSettings.OptionalSettings.BorderWidth ? trSettings.OptionalSettings.BorderWidth.dVal : 0.5);
	double nPatternWidth = (trSettings.OptionalSettings.PatternWidth ? trSettings.OptionalSettings.PatternWidth.dVal : 0.2); 
	int nFillColor = (trSettings.OptionalSettings.FillColor ? trSettings.OptionalSettings.FillColor.nVal : INDEX_COLOR_TRANSPARENT);

	bool bNoRotate = (trSettings.OptionalSettings.DisableRotate ? trSettings.OptionalSettings.DisableRotate.nVal : 0);
	bool bNoSkew = (trSettings.OptionalSettings.DisableSkew ? trSettings.OptionalSettings.DisableSkew.nVal : 0);
	bool bDeleteable = (trSettings.OptionalSettings.Deleteable ? trSettings.OptionalSettings.Deleteable.nVal : 1);//Sandy 2009-2-30 NO_SUPPOT_DEL_IN_PA_INTEGRATE, but default should can be deleted
	
	///---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
	string strEvent = (trSettings.OptionalSettings.Event ? trSettings.OptionalSettings.Event.strVal : "");
	///---END PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
	
	//object linked event info
	string strLTScript = "";
	if(trSettings.OptionalSettings.LTScript)
	{
		//strLTScript = trSettings.OptionalSettings.LTScript.strVal + "("+(string)m_nIndex + ");";
		// for any event, %1 from LT will have the event id
		strLTScript.Format("%s(%d, %%1)", trSettings.OptionalSettings.LTScript.strVal, m_nIndex);
	}

	int nEvent = (trSettings.OptionalSettings.EventID ? trSettings.OptionalSettings.EventID.nVal : GRCT_ANY_EVENT);
	////////----end of reading tree
	///////////////////////////////////////////////
	
	///Create Main Object
	if(nMainObj == GROT_ELLIPSE)
	{
		//if( !add_ellipse(lay, m_goMain, dX-dHalfW, dY-dHalfH, dX+dHalfW, dY+dHalfH, INDEX_COLOR_TRANSPARENT,  ATTACH_TO_SCALE,  false) )
		if( !add_ellipse(lay, m_goMain, dLeft, dBottom, dRight, dTop, INDEX_COLOR_TRANSPARENT,  nAttach,  false) )
			return false;			
	}
	else if(nMainObj == GROT_RECT)
	{
		//if( !add_rect(lay, m_goMain, dX-dHalfW, dY-dHalfH, dX+dHalfW, dY+dHalfH, INDEX_COLOR_TRANSPARENT,  ATTACH_TO_SCALE, LN_FREE, false,  false) )
		if( !add_rect(lay, m_goMain, dLeft, dBottom, dRight, dTop, INDEX_COLOR_TRANSPARENT,  nAttach, LN_FREE, false,  false) )
			return false;			
	}
	///Sandy 2007-4-18 add line as main object
	
	/// YuI 03/30/07 ~ is not valid character in gr object name
	// see is_graphic_object_valid in select.c
	//	string strName = m_strBaseName + "~"+(string)(m_nIndex);
	string strName = m_strBaseName + "_"+(string)(m_nIndex);
	/// end YuI
	
	m_goMain.SetName(strName);
	
	//Vertical Center Line
	//add_line(lay, m_goVCLine, dX, dY, ATTACH_TO_SCALE, nDir, true, false);
	//m_goVCLine.ConnectTo(m_goMain, -1, -1, false);
	//m_goVCLine.SetName(strName + "_VCLine");
	//m_goVCLine.Show(false);
	
	// the Line Lock to a Position
	if(bLine)
	{
		add_line(lay, m_goLine, dLineX, dY, ATTACH_TO_SCALE, nDir, true, false);
		m_goLine.SetName(strName + "_Line");
		disable_go_move(m_goLine, true, true, false, true);
		set_go_selectable(m_goLine, false);

	}
	
	if(bTitle)
	{
		double dWidth, dHeight;
		rect_get_size(m_goMain, dWidth, dHeight);
		add_text(lay, m_goTitle, dX, dY+dHeight*0.55, strTitle, 16, false);
		m_goTitle.ConnectTo(m_goMain, -1, -1, false);
		m_goTitle.SetName(strName + "_Title");
	}
	
	if(bLabel)
	{
		string strText;
		strText.Format(" %d ", nIndex);
		//add_label(lay, m_goLabel, dX , dY, strText);
		add_label(lay, m_goLabel, dLineX , dY, strText);//sandy 2008-10-22 make label always attach to the red line
		disable_go_move(m_goLabel, false, false, false);
		set_go_selectable(m_goLabel, false);
		//if(m_goLine)
			//m_goLabel.ConnectTo(m_goLine, -1, -1, false);	
		//else
		
		//sandy 2008-10-22 make label always attach to the red line
		//m_goLabel.ConnectTo(m_goMain, -1, -1, false);
		if(m_goLine)
			m_goLabel.ConnectTo(m_goLine, -1, -1, false);
		else
			m_goLabel.ConnectTo(m_goMain, -1, -1, false);
		m_goLabel.SetName(strName +"_Label");
	}
	
	//if(bHorizLine)
	//{
		//add_line(lay, m_goHLine, dLeft, dY, ATTACH_TO_SCALE, LN_HORIZONTAL, false, false, dRight, dY);
		//m_goHLine.SetName(strName + "_HorizLine");
		//disable_go_move(m_goHLine, true, true, false, true);
		//set_go_selectable(m_goHLine, false);		
	//}
	
	//shape_tool_init(m_goMain, nPatternColor, 1, 0.5, 0.2, INDEX_COLOR_TRANSPARENT);
	shape_tool_init(m_goMain, nPatternColor, nPatternStyle, nBorderWidth, nPatternWidth, nFillColor, bBehindData);
	set_go_behind_data(m_goMain, bBehindData);
	set_go_border_color(m_goMain, nBorderColor);
	disable_go_rotate_skew(m_goMain, bNoRotate, bNoSkew );
	//set_go_user_deleteable(m_goMain, true);//sandy 2009-3-2 NO_SUPPOT_DEL_IN_PA_INTEGRATE
	set_go_user_deleteable(m_goMain, bDeleteable);
	
	if(nMainObj == GROT_RECT)
		span_rect(m_goMain, nDir, bSpan) ;
	
		
	set_LT_script(m_goMain, strLTScript , nEvent);	
	///---Sim 12-11-2008 PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
	if ( !strEvent.IsEmpty() )
		m_goMain.SetEventHandler(strEvent);
	///---END PEAK_RECT_ADJUST_ON_PREVIEW_ALLOW_TO_APPLY_ALL_PEAKS
	
	return true;
}

bool ShapeControl::SetLinePos(double dX, int nUnitType)
{
	
	//string strName = m_goMain.GetName()+ "_Line";
	if(!m_goLine)
		return false;
	disable_go_move(m_goLine, true, true, false, true);
	if(!move_span_vline(m_goLine,dX, ATTACH_TO_SCALE, nUnitType))
		return false;
	disable_go_move(m_goLine, true, true, false, false);
	return true;
}
//
//bool ShapeControl::SetHorizLinePos(double dY, double dLeft, double dRight, int nUnitType)
//{
	//
	////string strName = m_goMain.GetName()+ "_Line";
	//if(!m_goHLine)
		//return false;
	//disable_go_move(m_goHLine, true, true, false, true);
	//if(move_hline(m_goHLine, dLeft, dRight, dY, nUnitType))
		//return false;
	//disable_go_move(m_goHLine, true, true, false, false);
	//return true;
//}
//
bool ShapeControl::GetLinePos(double& dX)
{
	if(!m_goLine)
		return false;
	
	dX = m_goLine.X;
	return true;
}

bool ShapeControl::SetLeftRight(double dxLeft, double dxRight, int nUnitType)
{
	/////sandy 2007-4-18 add horizontal line
	//if(m_goHLine)
		//SetHorizLinePos(m_goHLine.X, dxLeft, dxRight, nUnitType);
	

	return move_span_vrect(m_goMain, dxLeft, dxRight, ATTACH_TO_SCALE, nUnitType);
	//if(!rect_resize(m_goMain, dxRight - dxLeft))
		//return false;
	//
	//if(!move_span_vline(m_goVCLine, (dxLeft + dxRight)/2., ATTACH_TO_SCALE, nUnitType))
		//return false;
	//
	//return true;
}

//bool ShapeControl::SetWidth(double dWidth, int nUnitType)
//{
//
	//return rect_resize(m_goMain, dWidth, -1, nUnitType);
	//FRECT 	frThumb;
	//if( !m_goMain.GetTempBoundingBox(&frThumb) )
		//return false;	
	//
	//double dLeft, dRight, dX;
	//dLeft =	frThumb.left;
	//dRight = frThumb.right;
	//dX = (dRight + dLeft)/2.0;
	//
	//frThumb.left = dX - dWidth/2.0;
	//frThumb.right = dX + dWidth/2.0;
	//return true;
//}

//double ShapeControl::GetX(int nUnitType)
//{
	//double dLeft, dTop, dRight, dBottom;
	//if(!rect_get_position(m_goMain, dLeft, dTop, dRight, dBottom, -1))
		//return NANUM;
	//
	//return (dRight+dLeft)/2.;
//}

//double ShapeControl::GetLeft()
//{
	//double dLeft, dTop, dRight, dBottom;
	//if(!rect_get_position(m_goMain, dLeft, dTop, dRight, dBottom))
		//return NANUM;
	//
	//return dLeft;	
//}
//double ShapeControl::GetRight()
//{
	//double dLeft, dTop, dRight, dBottom;
	//if(!rect_get_position(m_goMain, dLeft, dTop, dRight, dBottom))
		//return NANUM;
	//
	//return dRight;	
//}
//
//double ShapeControl::GetWidth(int nUnitType)
//{
	//double dLeft, dTop, dRight, dBottom;
	//if(!rect_get_position(m_goMain, dLeft, dTop, dRight, dBottom, nUnitType))
		//return NANUM;	
		//
	//return (dRight-dLeft);
//}
//
//bool ShapeControl::GetPosition(double& dX, double& dY, double& dWidth, double& dHeight, double& dLeft, double& dRight)
bool ShapeControl::GetPosition(double& dX, double& dY,  double& dLeft, double& dRight, double& dTop, double& dBottom)
{
	//double dTop, dBottom;
	FRECT 	frThumb;
	
	/// RVD 2/9/2010 qa70-15085 SCALEIN_PA_PEAK_RECT_LIMITED
	//if( !m_goMain.GetTempBoundingBox(&frThumb) )
	if( !m_goMain.GetTempBoundingBox(&frThumb, GTBB_CALC) )
		return false;	
	/// end SCALEIN_PA_PEAK_RECT_LIMITED
		
	dLeft =	frThumb.left;
	dRight = frThumb.right;
	dTop =	max(frThumb.top, frThumb.bottom);
	dBottom = min(frThumb.top, frThumb.bottom);
	//--------

	///Sandy 2007-4-18 after add horizontal line
	//dX = (dRight+dLeft)/2.;
	//dY = (dTop+dBottom)/2.;
	if(!m_goLine)
		dX = (dRight+dLeft)/2.;
	else
		dX = m_goLine.X;
	
	dY = (dTop+dBottom)/2.;
	
	return true;
}

bool ShapeControl::MoveTo(double dLeft, double dRight , double dBottom, double dTop, int nUnit)
{
	return rect_move(m_goMain, dLeft, dTop, nUnit, dRight, dBottom);

}

ShapeControl::ShapeControl(Layer& lay, LPCSTR lpcszName)
{
	if(lay)
	{
		m_layParent = lay;
		/// Hong 12/26/08 v8.0991 IMPROVE_SPEED
		//foreach(GraphObject go in lay.GraphObjects)
		Collection<GraphObject>			goColl;
		lay.GetSpecialGraphicObjectsCollection(goColl, lpcszName);		
		foreach ( GraphObject go in goColl )
		/// end IMPROVE_SPEED
		{
			if(go.GetName() == lpcszName)
			{
				createFromMainObj(go);
				break;
			}
		}
	}
}

ShapeControl::ShapeControl(GraphObject & goOriginal)
{
	if(goOriginal)
	{
		goOriginal.GetParent(m_layParent);
		createFromMainObj(goOriginal);		
	}
}
bool ShapeControl::updateLable()
{
	if(!m_goLabel.IsValid())
		return false;
	string str;
	str.Format("%d",m_nIndex);
	m_goLabel.Text = str;
	return true;
}	

bool ShapeControl::updateObjsName()
{
	string str;
	str.Format("_%d",m_nIndex);
	
	if(!m_goMain.IsValid())
		return false;
	
	string strName = m_strBaseName + str;
	m_goMain.SetName(strName);	
	
	if(m_goLine)
		m_goLine.SetName(strName + "_Line");
	
	//if(m_goVCLine)
		//m_goVCLine.SetName(strName + "_VCLine");
	
	if(m_goTitle)
		m_goTitle.SetName(strName + "_Title");
	
	if(m_goLabel)
		m_goLabel.SetName(strName + "_Label");
	
	/////Sandy 2007-4-18 after add horizontal line
	//if(m_goHLine)
		//m_goLabel.SetName(strName + "_HorizLine");	

	return true;
}

void ShapeControl::SetIndex(int nIndex)
{
	m_nIndex = nIndex;
	updateLable();
	updateObjsName();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////member functons of ShapeControlList///////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ShapeControlList::ShapeControlList(Layer& lay, LPCSTR lpcszNameBase, int nMaxNum)
{
	if(lay && nMaxNum > 0)
	{
		m_strNameBase = lpcszNameBase;
		m_layParent = lay;
		m_nMaxNum = nMaxNum;
		updateMembersProperty();
	}
}


bool ShapeControlList::IsValid()
{
	if(!m_layParent)
		return false;
	
	/// Hong 12/26/08 v8.0991 IMPROVE_SPEED
	/*
	foreach(GraphObject go in m_layParent.GraphObjects)
	{
		string str = go.GetName();
		if(0 == strncmp(str, m_strNameBase, strlen(m_strNameBase)))
		{
	*/
	Collection<GraphObject>			goColl;
	if ( m_layParent.GetSpecialGraphicObjectsCollection(goColl, m_strNameBase) )
	{
		foreach ( GraphObject go in goColl )
		{			
	/// end IMPROVE_SPEED
			ShapeControl sc(go);// at least there are one ShapeControl Object is valid
			if(sc.IsValid())
				return true;
		}
	}		
	return false;
}
bool ShapeControlList::CreateList(Layer& lay, LPCSTR lpcszNameBase, int nMaxNum, int nNum, TreeNode& tr, int nMainObjType , BOOL bLine, BOOL bTitle, BOOL bLabel)//, BOOL bHorizLine)
{
	if(!lay.IsValid())
		return false;
	
	m_layParent = lay;
	m_strNameBase = lpcszNameBase;
	
	//string strLT = "label -r " + m_strNameBase + "*;";
	//LT_execute(strLT);
	//remove_GraphObjects_with_prefix(m_layParent, m_strNameBase);
	RemoveAll();
	if(nNum>nMaxNum||nNum<1)
		return false;
	
	//--Sandy 2008-12-17 ADD_PROGRESSBOX_AND_GIVE_USER_FEEDBACK_AND_CANCEL_WHEN_THE_PROGRESS_SLOW
	string strTitle = _L("Preparing Graph Objects......");
	string strTips;
	/// Kenny 12/24/2009 QA81-14875-P2 PROGRESS_BAR_IN_BUILTIN_TOOL_SHOULD_NOT_KEEP_TOPMOST
	//progressBox pb("", PBOX_TOPMOST, nNum < PAINT_NUM_PEAKS_THRESHOLD_TO_SHOW_PROGRESSBOX? true:false);
	progressBox pb("", PBOX_DEFAULT_STYLE, nNum < PAINT_NUM_PEAKS_THRESHOLD_TO_SHOW_PROGRESSBOX? true:false);
	/// End QA81-14875-P2 PROGRESS_BAR_IN_BUILTIN_TOOL_SHOULD_NOT_KEEP_TOPMOST
	pb.SetText(strTitle, PBOXT_TITLE);
	pb.SetRange(0,nNum);
	//--end ADD_PROGRESSBOX_AND_GIVE_USER_FEEDBACK_AND_CANCEL_WHEN_THE_PROGRESS_SLOW
	
	m_nCount = 0;
	//for(int ii = 1; ii <= nMaxNum; ii ++)
	for(int ii = 1; ii <= nNum; ii ++)
	{
		//--Sandy 2008-12-17 ADD_PROGRESSBOX_AND_GIVE_USER_FEEDBACK_AND_CANCEL_WHEN_THE_PROGRESS_SLOW
        strTips.Format(_L("Preparing Graph Objects, current is %d......"), ii);
        if(pb.Set(ii-1))
        {
            pb.SetText(strTips, PBOXT_MIDCENTER);
        }
        else
        {
            out_str("User abort!");
            break;
        }
        //--endADD_PROGRESSBOX_AND_GIVE_USER_FEEDBACK_AND_CANCEL_WHEN_THE_PROGRESS_SLOW  		
		

		LPCSTR Name = "s"+(string)ii;
		Tree trSettings;
		TreeNode trSc = tr.GetNode(Name);
		if(trSc.IsValid())
		{
			trSettings = trSc.Clone();
			if(tr.OptionalSettings)
				trSettings.AddNode(tr.OptionalSettings);		
			
			ShapeControl sc;
			if(sc.Create(lay, lpcszNameBase, ii, trSettings, nMainObjType, bLine, bTitle, bLabel ))//, bHorizLine))
			{
				m_nCount++;
			}
			
			/////Sandy 2007-4-18 if there horizontal line, hide the rectangle
			//if(bHorizLine)
				//sc.Show(false);
		}
	
		
		if(m_nCount >= nNum)
			break;
	}
	
	m_nCount = nNum;
	//m_nMaxNum = nMaxNum;
	m_nMaxNum = nNum;
	updateMembersProperty();
	
	return true;
}

/// Hong 12/26/08 v8.0991 IMPROVE_SPEED
/*
int ShapeControlList::updateMembersProperty()
{
	m_vnMembers.SetSize(0);
	m_vecX.SetSize(0);
	m_vecY.SetSize(0);
	//m_vecW.SetSize(0);
	//m_vecH.SetSize(0);
	m_vecLeft.SetSize(0);
	m_vecRight.SetSize(0);
	m_vecTop.SetSize(0);
	m_vecBottom.SetSize(0);
	m_vecLineX.SetSize(0);

	
	m_nCount = 0;
	for(int ii = 1; ii <= m_nMaxNum; ii ++)
	{
		ShapeControl sc;
		if(GetMember(sc, ii))
		{
			m_vnMembers.Add(sc.GetIndex());
			m_nCount ++;
			
			double dX, dY, dLeft, dRight, dLineX, dTop, dBottom;//dWidth, dHeight
			//sc.GetPosition(dX, dY, dWidth, dHeight,  dLeft,dRight);
			sc.GetPosition(dX, dY, dLeft,dRight, dTop, dBottom);
			
			m_vecX.Add(dX);
			m_vecY.Add(dY);
			//m_vecW.Add(dWidth);
			//m_vecH.Add(dHeight);
			m_vecLeft.Add(dLeft);
			m_vecRight.Add(dRight);
			m_vecTop.Add(dTop);
			m_vecBottom.Add(dBottom);
			
			sc.GetLinePos(dLineX);
			m_vecLineX.Add(dLineX);
		}
		//---
		
	}
	
	return m_nCount;
}
*/
int ShapeControlList::updateMembersProperty()
{
	int			nSize = m_nMaxNum;
	if ( nSize < 0 )
		nSize = 0;
	m_vnMembers.SetSize(nSize);
	m_vecX.SetSize(nSize);
	m_vecY.SetSize(nSize);
	m_vecLeft.SetSize(nSize);
	m_vecRight.SetSize(nSize);
	m_vecTop.SetSize(nSize);
	m_vecBottom.SetSize(nSize);
	m_vecLineX.SetSize(nSize);
	
	m_nCount = 0;
	for ( int ii = 1; ii <= m_nMaxNum; ii ++ )
	{
		ShapeControl sc;
		if ( GetMember(sc, ii) )
		{
			m_vnMembers[m_nCount] = sc.GetIndex();			
			
			double dX, dY, dLeft, dRight, dLineX, dTop, dBottom;
			bool	bRet = sc.GetPosition(dX, dY, dLeft,dRight, dTop, dBottom);
			ASSERT(bRet);
			
			m_vecX[m_nCount] = dX;
			m_vecY[m_nCount] = dY;			
			m_vecLeft[m_nCount] = dLeft;
			m_vecRight[m_nCount] = dRight;
			m_vecTop[m_nCount] = dTop;
			m_vecBottom[m_nCount] = dBottom;
			
			sc.GetLinePos(dLineX);
			m_vecLineX[m_nCount] = dLineX;
			
			m_nCount++;
		}		
	}
	ASSERT( m_vnMembers.GetSize() == m_vecX.GetSize() ); // All vector should be the same size
	if ( m_nCount != m_vnMembers.GetSize() )
	{
		m_vnMembers.SetSize(m_nCount);
		m_vecX.SetSize(m_nCount);
		m_vecY.SetSize(m_nCount);
		m_vecLeft.SetSize(m_nCount);
		m_vecRight.SetSize(m_nCount);
		m_vecTop.SetSize(m_nCount);
		m_vecBottom.SetSize(m_nCount);
		m_vecLineX.SetSize(m_nCount);
	}
	
	return m_nCount;
}
/// end IMPROVE_SPEED

bool ShapeControlList::GetMember(ShapeControl& sc, int nIndex)
{
	string strName = m_strNameBase +"_"+ (string)nIndex;
	ShapeControl scTemp(m_layParent, strName);
	if(!scTemp.IsValid())	
		return false;
	
	sc = scTemp;
	return true;
}

bool ShapeControlList::Sort()
{
	updateMembersProperty();
	
	vector<uint> vn;
	vector<uint> vnNew;
	
    m_vnMembers.Sort(SORT_ASCENDING, true, vn);
    
    m_vecX.Reorder(vn);
    m_vecY.Reorder(vn);
    //m_vecW.Reorder(vn);
    //m_vecH.Reorder(vn);
    m_vecLeft.Reorder(vn);
    m_vecRight.Reorder(vn);
    m_vecTop.Reorder(vn);
    m_vecBottom.Reorder(vn);
    
	m_vecLineX.Reorder(vn);
    
    vnNew.Data(1, m_vnMembers.GetSize(), 1);
  	
    for(int ii = 1; ii<=vnNew.GetSize(); ii++)
    {
    	//string strName = m_strNameBase +"~"+ (string)m_vnMembers[ii-1];
		//ShapeControl sc(m_layParent, strName);
		//sc.SetIndex(vnNew[ii-1]);
		ShapeControl sc;
		if(GetMember(sc, m_vnMembers[ii-1]))
    		sc.SetIndex(vnNew[ii-1]);
		//---
    }
    
	m_vnMembers = vnNew;
	return true;
}

bool ShapeControlList::Remove(GraphObject& go)
{
	ShapeControl sc(go);
	int nIndex = sc.GetIndex();
	return RemoveAt(nIndex);
}

bool ShapeControlList::RemoveAt(int nIndex)
{
	if(nIndex > m_nMaxNum || nIndex < 1)
		return false;

	//string strName = m_strNameBase +"~"+ (string)nIndex;
	//ShapeControl sc(m_layParent, strName);
	//if(!sc.IsValid())
		//return false;
	ShapeControl sc;
	if(!GetMember(sc, nIndex))
		return false;
	//---
	
	vector<uint> vn;
	if(m_vnMembers.Find(vn, nIndex) != 1)
		return false;

	m_vecX.RemoveAt(vn[0]);
	m_vecY.RemoveAt(vn[0]);
	//m_vecW.RemoveAt(vn[0]);
	//m_vecH.RemoveAt(vn[0]);
	m_vecLineX.RemoveAt(vn[0]);
	m_vecLeft.RemoveAt(vn[0]);
	m_vecRight.RemoveAt(vn[0]);
	m_vecTop.RemoveAt(vn[0]);
	m_vecBottom.RemoveAt(vn[0]);
	
	m_vnMembers.RemoveAt(vn[0]);
	

	sc.Remove();
	m_nCount--;
	
	return true;
}

bool ShapeControlList::RemoveAll()
{
	remove_GraphObjects_with_prefix(m_layParent, m_strNameBase);
	m_nCount = 0;
	return true;
}

bool ShapeControlList::Add(TreeNode& trSettings)
{
	if(m_nCount >= m_nMaxNum)
		return false;
	
	//string strName = m_strNameBase +"~"+ (string)m_vnMembers[0];
	//ShapeControl scLeader(m_layParent, strName);
	//if(!sc.IsValid())
		//return false;
	ShapeControl scLeader;
	if(!GetMember(scLeader, m_vnMembers[0]))
		return false;
	//---
	
	int nIndex = m_nCount+1;
	int nMainObjType = scLeader.GetMainObjType();
	bool bLine,  bTitle, bLabel;//, bHorizLine;
	scLeader.HasObjs(bLine,  bTitle, bLabel);//, bHorizLine);
	
	ShapeControl sc;
	if(!sc.Create(m_layParent, m_strNameBase, nIndex, trSettings, nMainObjType, bLine, bTitle, bLabel))//, bHorizLine))
		return false;

	updateMembersProperty();
	m_nCount++;
	return true;
}

bool ShapeControlList::SetPosition(vector& vxLeft, vector& vxRight, vector& vyTop, vector& vyBottom, int nUnitType, vector<uint>&vnIndex)
{
	updateMembersProperty();
	vector<uint> vnUse;
	if(vnIndex == NULL)
		vnUse = m_vnMembers;
	else
		vnUse = vnIndex;

	if(vxLeft.GetSize()!= vnUse.GetSize())
		return false;
	
	for(int ii = 0; ii<vnUse.GetSize(); ii++)
	{
		int nIndex = vnUse[ii];

		ShapeControl sc;
		if(GetMember(sc, nIndex))
		{
			sc.MoveTo(vxLeft[ii],vxRight[ii], vyTop[ii] ,vyBottom[ii], nUnitType);
		}
	}
	return true;	
}

bool ShapeControlList::GetPosition(vector& vxCenter, vector& vyCenter, vector& vxLeft, vector& vxRight, vector& vyTop, vector& vyBottom, vector<uint>&vnIndex)
{
	updateMembersProperty();
	vector<uint> vnUse;
	if(vnIndex == NULL)
		vnUse = m_vnMembers;
	else
		vnUse = vnIndex;

	//if(vxLeft.GetSize()!= vnUse.GetSize())
		//return false;
	
	int nSize = vnUse.GetSize();
	
	vxCenter.SetSize(nSize);
	vyCenter.SetSize(nSize);
	vxLeft.SetSize(nSize);
	vxRight.SetSize(nSize);
	vyTop.SetSize(nSize);
	vyBottom.SetSize(nSize);
	
	for(int ii = 0; ii<nSize; ii++)
	{
		int nIndex = vnUse[ii];

		ShapeControl sc;
		if(GetMember(sc, nIndex))
		{
			sc.GetPosition(vxCenter[ii], vyCenter[ii],  vxLeft[ii], vxRight[ii], vyTop[ii] , vyBottom[ii]);	
		}
	}
	return true;	
}


bool ShapeControlList::SetXPosition(vector& vxNew, vector& vxLeft, vector& vxRight, int nUnitType , vector<uint>&vnIndex)
{
	updateMembersProperty();
	vector<uint> vnUse;
	if(vnIndex == NULL)
		vnUse = m_vnMembers;
	else
		vnUse = vnIndex;

	if(vxNew.GetSize()!= vnUse.GetSize())
		return false;
	
	for(int ii = 0; ii<vnUse.GetSize(); ii++)
	{
		int nIndex = vnUse[ii];

		ShapeControl sc;
		if(GetMember(sc, nIndex))
		{
			//sc.SetWidth(vwNew[ii]);
			//sc.SetX(vxNew[ii]);
			sc.SetLinePos(vxNew[ii]);
			//sc.SetLeftRight(vxNew[ii]- vwNew[ii]/2.0,vxNew[ii]+ vwNew[ii]/2.0);
			sc.SetLeftRight(vxLeft[ii],vxRight[ii]);
		}
		//---
	
		
	}
	return true;
}

bool ShapeControlList::SetXPosition(TreeNode& tr)
{
	if(!tr.IsValid())
		return false;
	
	int nCount = 0;
	vector<uint> vnNewIndex(0);
	foreach(TreeNode trN in tr.Children)
	{
		if(nCount >= m_nCount)
			break;
		
		if(!trN.Width || !trN.X)
			continue;
		
		ShapeControl sc;
		if(GetMember(sc, m_vnMembers[nCount]))
		{

			//sc.SetWidth(trN.Width.dVal);
			//sc.SetX(trN.X.dVal);
			//sc.SetLeftRight(trN.X.dVal - trN.Width.dVal/2.0,trN.X.dVal + trN.Width.dVal/2.0);
			if(trN.Left && trN.Right)
				sc.SetLeftRight(trN.Left.dVal,trN.Right.dVal);
		
		}
		
		nCount++;
	}
	
	updateMembersProperty();
	return true;
}

//bool ShapeControlList::GetXPosition(vector& vx, vector& vw, vector<uint>&vnIndex)
//{
	//updateMembersProperty();
	//vector<uint> vnUse;
	//if(vnIndex == NULL)
		//vnUse = m_vnMembers;
	//else
		//vnUse = vnIndex;
//
	//vx.SetSize(vnUse.GetSize());
	//vw.SetSize(vnUse.GetSize());
	//
	//for(int ii = 0; ii<vnUse.GetSize(); ii++)
	//{
		//int nIndex = vnUse[ii];
//
		//ShapeControl sc;
		//if(GetMember(sc, nIndex))
		//{
			////sc.GetWidth(vw[ii]);
			////sc.GetX(vx[ii]);
			//double dX, dY, dLeft, dRight;//, dWidth, dHeight
			////sc.GetPosition(dX, dY, dWidth, dHeight,  dLeft,dRight);	
			//sc.GetPosition(dX, dY,  dLeft,dRight);	
			//vw[ii] = dWidth;
			//vx[ii] = dX;
		//}
		//
	//}
	//return true;
//}
//
bool ShapeControlList::GetXBoundarys(vector& vxLeft, vector& vxRight, vector<uint>&vnIndex )
{
	updateMembersProperty();
	vector<uint> vnUse;
	if(vnIndex == NULL)
		vnUse = m_vnMembers;
	else
		vnUse = vnIndex;

	vxLeft.SetSize(vnUse.GetSize());
	vxRight.SetSize(vnUse.GetSize());

	for(int ii = 0; ii<vnUse.GetSize(); ii++)
	{
		int nIndex = vnUse[ii];

		ShapeControl sc;
		if(GetMember(sc, nIndex))
		{
			//double dX, dW;
			//dW = sc.GetWidth();
			//dX = sc.GetX();
			double dX, dY, dLeft, dRight, dTop, dBottom;// dWidth, dHeight,
			//sc.GetPosition(dX, dY, dWidth, dHeight,  dLeft,dRight);
			sc.GetPosition(dX, dY, dLeft,dRight, dTop, dBottom);
			
			vxLeft[ii] = dLeft;//dX -dWidth/2.0;
			vxRight[ii] = dRight;//dX +dWidth/2.0;
		}
		
	}
	return true;
}
//can be saved to GetN tree to support theme
///Sandy 2008-3-17 remove data id since this is not a good solution
bool ShapeControlList::SaveToTree(TreeNode& tr)
{
	if(!tr.IsValid())
		return false;

	updateMembersProperty();
	ShapeControl scLeader;
	if(!GetMember(scLeader, m_vnMembers[0]))
		return false;
	
	for(int ii = 0; ii < m_vnMembers.GetSize(); ii ++)
	{

		
		//int nID = IDE_ANCHOR_ID + m_vnMembers[ii] ;
		LPCSTR lpcszTag = "s"+(string)m_vnMembers[ii];
		//string strTagName = "s"+(string)m_vnMembers[ii];
		//tree_check_get_node_by_dataid(tr, trControl, lpcszTag, nID);
		TreeNode trControl = tree_check_get_node(tr, lpcszTag);
		// initialize info
		/*
		//TreeNode trIndex, trX, trY, trW, trH;
		TreeNode trIndex, trX, trY, trL, trR, trLX, trT, trB;
		tree_check_get_node_by_dataid(trControl, trIndex, "Index", nID+IDE_ATTR_BIT_ANCHOR_I);
		tree_check_get_node_by_dataid(trControl, trX, "X", nID+IDE_ATTR_BIT_ANCHOR_X);
		tree_check_get_node_by_dataid(trControl, trY, "Y", nID+IDE_ATTR_BIT_ANCHOR_Y);
		//tree_check_get_node_by_dataid(trControl, trW, "Width", nID+IDE_ATTR_BIT_ANCHOR_W);
		//tree_check_get_node_by_dataid(trControl, trH, "Height", nID+IDE_ATTR_BIT_ANCHOR_H);
		tree_check_get_node_by_dataid(trControl, trL, "Left", nID+IDE_ATTR_BIT_ANCHOR_LEFT);
		tree_check_get_node_by_dataid(trControl, trR, "Right", nID+IDE_ATTR_BIT_ANCHOR_RIGHT);
		tree_check_get_node_by_dataid(trControl, trT, "Top", nID+IDE_ATTR_BIT_ANCHOR_TOP);
		tree_check_get_node_by_dataid(trControl, trB, "Bottom", nID+IDE_ATTR_BIT_ANCHOR_BOTTOM);
		
		
		tree_check_get_node_by_dataid(trControl, trLX, "LineX", nID+IDE_ATTR_BIT_ANCHOR_LINE_X);
		*/
		TreeNode trIndex = tree_check_get_node(trControl, "Index");
		TreeNode trX  = tree_check_get_node(trControl, "X");
		TreeNode trY = tree_check_get_node(trControl, "Y");
		TreeNode trL = tree_check_get_node(trControl, "Left");
		TreeNode trR = tree_check_get_node(trControl, "Right");
		TreeNode trT = tree_check_get_node(trControl, "Top");
		TreeNode trB = tree_check_get_node(trControl, "Bottom");
		TreeNode trLX = tree_check_get_node(trControl, "LineX");		
		
		trIndex.nVal = m_vnMembers[ii];
		trX.dVal = m_vecX[ii];
		trY.dVal = m_vecY[ii];
		//trW.dVal = m_vecW[ii];
		//trH.dVal = m_vecH[ii];
		trL.dVal = m_vecLeft[ii];
		trR.dVal = m_vecRight[ii];
		trT.dVal = m_vecTop[ii];
		trB.dVal = m_vecBottom[ii];
		
		trLX.dVal = m_vecLineX[ii];

		
	}

	///Sandy 2007-8-17 no need to save the optional setting
	//TreeNode trOptionalSettings;
	//int nID = IDE_ANCHOR_SETTING_ID;
	//tree_check_get_node_by_dataid(tr, trOptionalSettings, "OptionalSettings", nID);
	////general optional info
	//TreeNode trSpan, trDir, trTitle, trColor, trLTScript, trEventID, trBHData;
	//tree_check_get_node_by_dataid(trOptionalSettings, trSpan, "Span", nID+IDE_ATTR_BIT_ANCHOR_SPAN);
	//tree_check_get_node_by_dataid(trOptionalSettings, trDir, "Dir", nID+IDE_ATTR_BIT_ANCHOR_DIR);
	//tree_check_get_node_by_dataid(trOptionalSettings, trBHData, "BehindData", nID+IDE_ATTR_BIT_ANCHOR_BEHINDDATA);
	//tree_check_get_node_by_dataid(trOptionalSettings, trTitle, "Title", nID+IDE_ATTR_BIT_ANCHOR_TITLE);
	//tree_check_get_node_by_dataid(trOptionalSettings, trColor, "Color", nID+IDE_ATTR_BIT_ANCHOR_COLOR);
	//tree_check_get_node_by_dataid(trOptionalSettings, trLTScript, "LTScript", nID+IDE_ATTR_BIT_ANCHOR_LTSCRIPT);
	//tree_check_get_node_by_dataid(trOptionalSettings, trEventID, "EventID", nID+IDE_ATTR_BIT_ANCHOR_EVENTID);	
	//scLeader.GetOptionalSettings(trOptionalSettings);	
	

	//TreeNode trMaxNum;
	//tree_check_get_node_by_dataid(tr, trMaxNum,"MaxNumber", IDE_ANCHOR_MAX_NUM);
	TreeNode trMaxNum = tree_check_get_node(tr, "MaxNumber");	
	trMaxNum.nVal = m_nMaxNum;
	
	//TreeNode trNum;
	//tree_check_get_node_by_dataid(tr, trNum,"Number", IDE_ANCHOR_NUMBER);
	TreeNode trNum = tree_check_get_node(tr, "Number");	
	trNum.nVal = m_nCount;
	
//
	//TreeNode trType, trHasLine, trHasTitle, trHasLabel, trHasHLine;
	//tree_check_get_node_by_dataid(tr, trType,"Type", IDE_ATTR_BIT_ANCHOR_TYPE);
	//tree_check_get_node_by_dataid(tr, trHasLine,"HasLine", IDE_ATTR_BIT_ANCHOR_HAS_LINE);
	//tree_check_get_node_by_dataid(tr, trHasTitle,"HasTitle", IDE_ATTR_BIT_ANCHOR_HAS_TITLE);
	//tree_check_get_node_by_dataid(tr, trHasLabel,"HasLabel", IDE_ATTR_BIT_ANCHOR_HAS_LABEL);

	TreeNode trType = tree_check_get_node(tr, "Type");	
	TreeNode trHasLine = tree_check_get_node(tr, "HasLine");	
	TreeNode trHasTitle = tree_check_get_node(tr, "HasTitle");	
	TreeNode trHasLabel = tree_check_get_node(tr, "HasLabel");	
	TreeNode trHasHLine = tree_check_get_node(tr, "HasHorizLine");	
	/////sandy 2007-4-18 add HorizonLine
	//tree_check_get_node_by_dataid(tr, trHasHLine,"HasHorizLine", IDE_ATTR_BIT_ANCHOR_HAS_HLINE);
	
	trType.nVal = scLeader.GetMainObjType();
	bool bLine,  bTitle, bLabel;//, bHorizLine;
	scLeader.HasObjs(bLine,  bTitle, bLabel);//, bHorizLine);
	trHasLine.nVal = bLine;
	trHasTitle.nVal = bTitle;
	trHasLabel.nVal = bLabel;
	///sandy 2007-4-18 add HorizonLine
	//trHasHLine.nVal = bHorizLine;
	
	
	return true;	
}



/// YuI 02/05/08 WORK_ON_SPFW
bool	ShapeControlList::FixPositions(bool bFix)
{
	int nPeaks = GetCount();
	for( int ii = 0; ii < nPeaks; ii++ )
	{
		ShapeControl sc;
		if( GetMember(sc, m_vnMembers[ii]) )
		{
			GraphObject go = sc.GetMainObj();
			if (!disable_go_move(go, true, true, true, !bFix))
				return false;
		}
	}	
	
	return true;
}
/// end WORK_ON_SPFW

///Sandy 2008-3-17 remove data id since this is not a good solution

//bool init_setting_tree_for_ShapeControl(TreeNode& tr, int nMaxNum)
//{
	//if(!tr.IsValid())
		//return false;
	//
	//
	//for(int ii = 1; ii <= nMaxNum; ii ++)
	//{
//
		////int nID = IDE_ANCHOR_ID + ii;
//
		//LPCSTR lpcszTag = "s"+(string)ii;
		////tree_check_get_node_by_dataid(tr, trControl, lpcszTag, nID);
		//TreeNode trControl = tree_check_get_node(tr,  lpcszTag);
//
		/////Sandy 2008-3-17 remove data id since this is not a good solution
		///*
		//// initialize info
		////TreeNode trIndex, trX, trY, trW, trH;
		//TreeNode trIndex, trX, trY, trL, trR, trLX;
		//tree_check_get_node_by_dataid(trControl, trIndex, "Index", nID+IDE_ATTR_BIT_ANCHOR_I);
		//tree_check_get_node_by_dataid(trControl, trX, "X", nID+IDE_ATTR_BIT_ANCHOR_X);
		//tree_check_get_node_by_dataid(trControl, trY, "Y", nID+IDE_ATTR_BIT_ANCHOR_Y);
		////tree_check_get_node_by_dataid(trControl, trW, "Width", nID+IDE_ATTR_BIT_ANCHOR_W);
		////tree_check_get_node_by_dataid(trControl, trH, "Height", nID+IDE_ATTR_BIT_ANCHOR_H);
		//tree_check_get_node_by_dataid(trControl, trL, "Left", nID+IDE_ATTR_BIT_ANCHOR_LEFT);
		//tree_check_get_node_by_dataid(trControl, trR, "Right", nID+IDE_ATTR_BIT_ANCHOR_RIGHT);
		//tree_check_get_node_by_dataid(trControl, trLX, "LineX", nID+IDE_ATTR_BIT_ANCHOR_LINE_X);
		//*/
		//TreeNode trIndex = tree_check_get_node(trControl, "Index");
		//TreeNode trX  = tree_check_get_node(trControl, "X");
		//TreeNode trY = tree_check_get_node(trControl, "Y");
		//TreeNode trL = tree_check_get_node(trControl, "Left");
		//TreeNode trR = tree_check_get_node(trControl, "Right");
		//TreeNode trLX = tree_check_get_node(trControl, "LineX");
//
		//trIndex.nVal = ii;
		//trX.dVal = 0;
		//trY.dVal = 0;
		//trL.dVal = 0;
		//trR.dVal = 0;
		//trLX.dVal = 0;
	//}
//
	//TreeNode trMaxNum;
	//tree_check_get_node_by_dataid(tr, trMaxNum,"MaxNumber", IDE_ANCHOR_MAX_NUM);
	//trMaxNum.nVal = nMaxNum;
	//
	//return true;
//}

/// Hong 04/19/07 v8.0604 NEW_LINE_CONTROL_CLASS_FOR_PFM_XF_NEEDED_BY_SANDY
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////member functons of LineControl////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
LineControl::LineControl(const GraphObject & goOriginal)
{
	m_bValid = Init(goOriginal);
}

LineControl::LineControl(const GraphLayer& gl, LPCSTR lpcszName)
{
	m_bValid = false;
	
	if(gl)
	{
		GraphObject gr;
		gr = gl.GraphObjects(lpcszName);
		
		m_bValid = Init(gr);
	}
}

bool LineControl::Init(const GraphObject & goOriginal)
{
	if ( goOriginal )
	{
		m_goLine = goOriginal;

		vector<uint> vnUIDs;
		if(m_goLine.GetConnectedObjects(vnUIDs) > 0)
		{
			GraphObject goText;
			goText = Project.GetObject(vnUIDs[0]);
			
			string strTextName = m_goLine.GetName() + "_Label";
			if (goText && ( 0 == strTextName.CompareNoCase(goText.GetName()) ) )
			{
				m_goLabel = goText;
				return true;
			}			
		}
	}
	
	return false;
}

bool LineControl::Create(const GraphLayer& gl, LPCSTR lpcszName, double dX, LPCSTR lpcszLabel, LPCSTR lpcszLTScript) // = NULL, = NULL
{
	string strObjName(lpcszName);
	
	if ( !gl || strObjName.IsEmpty() )
		return false;
	// remove existing object
	gl.RemoveGraphObject(strObjName);
	gl.RemoveGraphObject(strObjName + "_Label");
	
	add_line(gl, m_goLine, dX, 0, ATTACH_TO_SCALE, LN_VERTICAL, true, false);
	disable_go_move(m_goLine, false, false, false);
	m_goLine.SetName(strObjName);
	
	if ( lpcszLTScript != NULL )
	{
		//set_LT_script(m_goLine, lpcszLTScript, GRCT_ANY_EVENT);
		set_LT_script(m_goLine, lpcszLTScript, GRCT_MOVE);
	}
	
	string strText;
	if (lpcszLabel != NULL)
		strText = lpcszLabel;
	else
		strText = strObjName;
	
	double dY = ( gl.Y.To + gl.Y.From ) / 2;
	add_label(gl, m_goLabel, dX , dY, strText);
	m_goLabel.SetName(strObjName + "_Label");
	set_go_selectable(m_goLabel, false);
	m_goLabel.ConnectTo(m_goLine, -1, -1, false);
	
	return true;
}

bool LineControl::UpdateLabel(LPCSTR lpcszLabel)
{
	if ( !IsValid() )
		return false;
	
	m_goLabel.Text = lpcszLabel;
	return true;
}

bool LineControl::Show(bool bShow) // add by sandy 2008-1-7
{
	if ( !IsValid() )
		return false;
	
	m_goLine.Show(bShow);
	m_goLabel.Show(bShow);
	return true;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////member functons of LineControlList////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
LineControlList::LineControlList(const GraphLayer& gl, LPCSTR lpcszNameBase) 
{
	Reset();
	
	string strNameBase(lpcszNameBase);
	
	if ( gl && !strNameBase.IsEmpty() )
	{
		m_glTarget = gl;
		
		foreach(GraphObject go in m_glTarget.GraphObjects)
		{
			string strName;
			strName = go.GetName();
			if ( -1 == m_vstrObjName.Find(strName) ) // avoid duplicate
			{
				LineControl lc(m_glTarget, strName);
				
				if ( lc.IsValid() )
				{
					m_vstrObjName.Add(strName);
				}
			}
		}
	}
}

int LineControlList::CreateList(const GraphLayer& gl, LPCSTR lpcszNameBase, const vector& vdX, LPCSTR lpcszLTScript) //= NULL
{
	Reset();
	
	string strNameBase(lpcszNameBase);
	if ( !gl || 0 == vdX.GetSize() || strNameBase.IsEmpty() )
		return 0;
	
	m_glTarget = gl;
	
	///Sandy 2007-6-6 the index should start with 1, not 0
	//for (int ii=0; ii < vdX.GetSize(); ii++)
	for (int ii=1; ii <= vdX.GetSize(); ii++)
	{
		string strLabel;
		//strLabel.Format(" %d ", ii+1); //1 offset
		strLabel.Format(" %d ", ii); //1 offset
		string strObjName;
		strObjName = strNameBase + "_" + ii;
		LineControl lc;
		//if ( lc.Create(gl, strObjName, vdX[ii], strLabel, lpcszLTScript) )
		if ( lc.Create(gl, strObjName, vdX[ii-1], strLabel, lpcszLTScript) )
			m_vstrObjName.Add(strObjName);
	}
	
	return m_vstrObjName.GetSize();
}

LineControl LineControlList::GetAt(int nIndex)
{
	LineControl lctrlInvalid;

	if ( !IsValid() || nIndex > m_vstrObjName.GetSize() || nIndex < 0  )
		return lctrlInvalid;
	
	LineControl lineCtrl(m_glTarget, m_vstrObjName[nIndex]);
	
	return lineCtrl;
}


int LineControlList::RemoveAt(int nIndex, bool bUpdateLabels)
{
	if ( !IsValid() || nIndex > m_vstrObjName.GetSize() || nIndex < 0 )
		return -1;
	
	m_glTarget.RemoveGraphObject(m_vstrObjName[nIndex]);
	
	m_glTarget.RemoveGraphObject(m_vstrObjName[nIndex] + "_Label");
	
	m_vstrObjName.RemoveAt(nIndex);
	
	//UpdateLabels(nIndex+1);
	if(bUpdateLabels)
		UpdateLabels(nIndex+1);
	
	return nIndex;
}

int LineControlList::Remove(LPCSTR lpcszName)
{
	int nPos = m_vstrObjName.Find(lpcszName);
	
	return RemoveAt(nPos);
}

int LineControlList::RemoveAll()
{
	int nCount = 0;
	
	if ( !IsValid() )
		return 0;
	
	for (int ii=GetCount(); ii > 0; ii--) // remove from the end to avoid problem of m_vnPlotIndex size
	{
		if ( -1 != RemoveAt(ii - 1, false) ) 
			nCount++;
	}
	
	return nCount;
}

int LineControlList::Add(double dX, LPCSTR lpcszLTScript, bool bReplace) // = NULL, = true
{
	int nIndex = -1;
	
	if ( !IsValid() )
		return nIndex;
	
	string strName;
	strName = m_vstrObjName[0].GetToken(0, '_');
	
	int nSize = GetCount() + 1;
	///Sandy 2007-6-6 the index should start with 1, not 0
	//for (int ii=0; ii < nSize; ii++) // get valid object name
	for (int ii=1; ii <= nSize; ii++)
	{
		string strTemp = strName + "_" + ii;
		if ( -1 == m_vstrObjName.Find(strTemp) )
		{
			strName = strTemp;
			break;
		}
	}
	
	string strLabel;
	strLabel.Format(" %d ", GetCount()+1);
	LineControl listCtrl;
	if ( listCtrl.Create(m_glTarget, strName, dX, strLabel, lpcszLTScript) )
		nIndex = m_vstrObjName.Add(strName);

	return nIndex;
}

int LineControlList::GetLinePositions(vector& vdX)
{
	if ( !IsValid() )
		return 0;
	
	vdX.SetSize(0); //reset
	
	int nCount = 0;
	for (int ii=0; ii< GetCount(); ii++)
	{
		LineControl listCtrl(m_glTarget, m_vstrObjName[ii]);
		
		if ( listCtrl.IsValid() )
		{
			vdX.Add(listCtrl.GetLinePos());
			nCount++;
		}
	}
	
	return nCount;
}

int LineControlList::UpdateLabels(int nOffset)
{
	int nCount = 0;
	///Sandy 2007-6-6 the index should start with 1, not 0
	//for (int ii=nOffset; ii < GetCount(); ii++)
	for (int ii=nOffset; ii <= GetCount(); ii++)
	{
		string strLabel;
		//strLabel.Format(" %d ", ii+1); //1 offset
		strLabel.Format(" %d ", ii); //1 offset
		//LineControl listCtrl(m_glTarget, m_vstrObjName[ii]);
		LineControl listCtrl(m_glTarget, m_vstrObjName[ii-1]);
		if ( listCtrl.IsValid() )		
		{
			listCtrl.UpdateLabel(strLabel);
			nCount++;
		}
	}
	
	return nCount;
}

int LineControlList::ShowAll(bool bShow)
{
	if ( !IsValid() )
		return 0;
	

	int nCount = 0;
	for (int ii=0; ii< GetCount(); ii++)
	{
		LineControl listCtrl(m_glTarget, m_vstrObjName[ii]);
		
		if ( listCtrl.IsValid() )
		{
			listCtrl.Show(bShow);
		}
	}
	
	return nCount;
}

/// Hong 03/26/08 v8/0832b PA_PEAKS_DEL_REQUIRE_FOLLOWING_DATA_SUPPORT
//bool select_data_points_from_active_graph(vector& vx, vector& vy, vector<int>& vSelIndex, LPCSTR lpcszMsg1, LPCSTR lpcszMsg2, double dErrX , double dErrY)
bool select_data_points_from_active_graph(vector& vx, vector& vy, vector<int>& vSelIndex, LPCSTR lpcszMsg1, LPCSTR lpcszMsg2, double dErrX , double dErrY, int* pnPlotIndex) // NULL
/// end PA_PEAKS_DEL_REQUIRE_FOLLOWING_DATA_SUPPORT
{
	if(vx.GetSize() != vy.GetSize() || vx.GetSize() <= 0)
		return false;
	
	///Sandy 2008-3-17 use absolute error since there maybe only one component in vx and vy
	//double dMin, dMax;
	//vx.GetMinMax(dMin, dMax);
	//dErrX = abs((dMax - dMin) * dErrX);
	//
	//vy.GetMinMax(dMin, dMax);
	//dErrY = abs((dMax - dMin) * dErrY);
	
	vector vsx, vsy;
	/// Hong 03/26/08 v8/0832b PA_PEAKS_DEL_REQUIRE_FOLLOWING_DATA_SUPPORT
	//if(0<graph_get_points(vsx, vsy, -1, -1, lpcszMsg1, lpcszMsg2 ))
	if ( 0 < graph_get_points(vsx, vsy, lpcszMsg1, lpcszMsg2, pnPlotIndex) )
	/// end PA_PEAKS_DEL_REQUIRE_FOLLOWING_DATA_SUPPORT
	{
		vSelIndex.SetSize(vsx.GetSize());
		vSelIndex = -1;//default is no seletion
		for(int ii = 0; ii<vsx.GetSize(); ii++)
		{
			vector<uint> vecXIndex, vecYIndex;
			int nFound;
			if( 1 <= vx.Find(vecXIndex, vsx[ii]-dErrX, vsx[ii]+dErrX)	&& 1 <= vy.Find(vecYIndex, vsy[ii]-dErrY, vsy[ii]+dErrY) )
			{
				vSelIndex[ii] = vecXIndex[0];
			}
		}
	}
	else
		return false;
	
	return true;
}

/// Hong 03/26/08 v8/0832b PA_PEAKS_DEL_REQUIRE_FOLLOWING_DATA_SUPPORT
//bool delete_data_points_from_graph(vector& vx, vector& vy, vector<int>& vDelIndex, LPCSTR lpcszMsg1, LPCSTR lpcszMsg2, double dErrX , double dErrY)
bool delete_data_points_from_graph(vector& vx, vector& vy, vector<int>& vDelIndex, LPCSTR lpcszMsg1, LPCSTR lpcszMsg2, double dErrX , double dErrY, int* pnPlotIndex) // NULL, NULL, 0.05, 0.05, NULL
/// end PA_PEAKS_DEL_REQUIRE_FOLLOWING_DATA_SUPPORT
{
	if(vx.GetSize() != vy.GetSize() || vx.GetSize() <= 0)
		return false;
	/// Hong 03/26/08 v8/0832b PA_PEAKS_DEL_REQUIRE_FOLLOWING_DATA_SUPPORT
	//if(!select_data_points_from_active_graph(vx, vy, vDelIndex, lpcszMsg1, lpcszMsg2, dErrX ,dErrY))
	if(!select_data_points_from_active_graph(vx, vy, vDelIndex, lpcszMsg1, lpcszMsg2, dErrX ,dErrY, pnPlotIndex))
	/// end PA_PEAKS_DEL_REQUIRE_FOLLOWING_DATA_SUPPORT
		return false;
	
	for(int ii = 0; ii < vDelIndex.GetSize(); ii++)
	{
		if(vDelIndex[ii] != -1)
		{
			vx[vDelIndex[ii]] = NANUM;
			vy[vDelIndex[ii]] = NANUM;
		}
	}
	
	vx.Trim();
	vy.Trim();
	return true;
}

///Sandy add 2008-2-21
bool delete_data_points_of_dataplot_from_graph(DataPlot& dp, vector<int>& vDelIndex,  LPCSTR lpcszMsg1, LPCSTR lpcszMsg2, double dErrX , double dErrY)
{
	if(!dp.IsValid())
		return false;
	
	GraphLayer gl;
	
	dp.GetParent(gl);
	
	if(!gl)
		return false;
	
	XYRange xy;
	if(!dp.GetDataRange(xy))
		return false;
	
	vector vx, vy;
	if(!xy.GetData(vy, vx) || vx.GetSize() <=0)
		return false;
	
	if(!delete_data_points_from_graph(vx, vy, vDelIndex, lpcszMsg1, lpcszMsg2, dErrX , dErrY))
		return false;
	
	if(!xy.SetData(&vy, &vx))
		return false;	
		
	return true;
	
}

/// Fisher 2008-9-19
GraphObject& get_master_gr(GraphObject &go)
{
	/// YuI 09/23/08 by CP's request cleaning unnecesary code
	/*
	if(!go)
		return NULL;
	Tree tr;
	go.GetBinaryStorage(MASTER, tr);
	if(!tr || !tr.master)
		return NULL;
	GraphLayer gl;
	go.GetParent(gl);
	return gl.GraphObjects(tr.master.strVal);
	*/
	if( !go )
		return NULL;
		
	vector<uint>	vUIDs;
	if ( go.GetConnectedObjects( vUIDs ) > 0 )
	{
		return Project.GetObject(vUIDs[0]); 
	}
	
	return NULL;
	/// end YuI 09/23/08 
}
/// End Fisher


/////Sandy 2008-9-9 QA80-12141 XYRANGE_PLOT_LABELS_WITHOUT_L_COL 
//bool set_plot_XY_values_as_labels(DataPlot& dp, int nSymbolType)
//{
	//if(!dp.IsValid())
		//return false;
	//
	//
	////set row number symbol type
	//int nn = 4;
	//dp.LabTalk("kt", &nn);
	//
	////set XY
	//nn = nSymbolType;
	//dp.LabTalk("kf", &nn);
	//
	//return true;
//
//}

///Jasmine 03/15/08 CP_ASK_MOVE_CPEAKSPREVIEWHELPER_FROM_SPFM_UTILS
string get_shape_control_indexed_name(LPCSTR lpcszName, int nIndex)
{
	string str;
	str.Format("%s_%d", lpcszName, nIndex);
	return str;
}

//----------------------------------------------------------
void	GetROIGraphicObjectSettings(TreeNode& trSettings)
{
	trSettings.X.dVal = 0;
	trSettings.Y.dVal = 0;
	trSettings.Left.dVal = 0;
	trSettings.Right.dVal = 0;
	trSettings.Top.dVal = 0;
	trSettings.Bottom.dVal = 0;
	//----- CPY 4/8/08 NANOSIZER_ROI_SHOULD_BE_BLACK_SINCE_SRC_CONTOUR_IS_CHANGED_TO_COLOR
	//trSettings.OptionalSettings.BorderColor.nVal = SYSCOLOR_RED;
	trSettings.OptionalSettings.BorderColor.nVal = SYSCOLOR_BLACK;
	//-----
	trSettings.OptionalSettings.LTScript.strVal = "_event_from_graph_object_ROI";
	GetROIPeakGraphicObjectOptionalSettings(trSettings);
}
void	GetPeakGraphicObjectSettings(TreeNode& trSettings, double dX, double dY, double dXWidth, double dYWidth, BOOL bOptional)
{
	trSettings.X.dVal = dX;
	trSettings.Y.dVal = dY;
	trSettings.Left.dVal = dX - dXWidth / 2;
	trSettings.Right.dVal = dX + dXWidth / 2;
	trSettings.Top.dVal = dY - dYWidth / 2;
	trSettings.Bottom.dVal = dY + dYWidth / 2;
	trSettings.OptionalSettings.BorderColor.nVal = SYSCOLOR_BLACK;	///Jasmine 03/31/08 CP said Preview contour should use color and peak circles should use black
	trSettings.OptionalSettings.LTScript.strVal = "_event_from_graph_object_peak";
	
	if( bOptional )
	{
		GetROIPeakGraphicObjectOptionalSettings(trSettings);
	}
}

void	GetROIPeakGraphicObjectOptionalSettings(TreeNode& trSettings)
{
	trSettings.OptionalSettings.Span.nVal  = false;
	trSettings.OptionalSettings.Dir.nVal = LN_FREE;
	trSettings.OptionalSettings.BehindData.nVal = false;
	
	trSettings.OptionalSettings.PatternStyle.nVal = 7;//dense;
	trSettings.OptionalSettings.BorderWidth.dVal  = 5;
	trSettings.OptionalSettings.PatternWidth.dVal = 0.01;
	trSettings.OptionalSettings.FillColor.nVal =INDEX_COLOR_TRANSPARENT;	
	
	trSettings.OptionalSettings.EventID.nVal = GRCT_ANY_EVENT;//GRCT_SIZEMOVE;
}


////////////////////////////////////////////////////////////
// class	CPeaksPreviewHelper
////////////////////////////////////////////////////////////
CPeaksPreviewHelper::CPeaksPreviewHelper(GraphLayer gl)
{
	m_gl = gl;
}

//----------------------------------------------------------
/// Hong 03/20/08 v8.0828 EMPTY_DESTRUCTOR_LEAD_XF_PKFIND_LINKING_ERROR_UNEXPECTED
/*
CPeaksPreviewHelper::~CPeaksPreviewHelper()
{
}
*/
/// end EMPTY_DESTRUCTOR_LEAD_XF_PKFIND_LINKING_ERROR_UNEXPECTED

//----------------------------------------------------------
GraphLayer	CPeaksPreviewHelper::GetLayer()
{
	return m_gl;
}

//----------------------------------------------------------
void	CPeaksPreviewHelper::Reset()
{
	GraphLayer	gly = Project.ActiveLayer();
	if( gly.IsValid() )
	{
		Collection<GraphObject>	coll;
		if ( gly.GetSpecialGraphicObjectsCollection(coll, _NANO_PEAKS_REG_NAME) )
		{
			GraphObject grDestroy;
			foreach( GraphObject gr in coll )
			{
				if( grDestroy )
					grDestroy.Destroy();
				grDestroy = gr;
			}
			if( grDestroy )
				grDestroy.Destroy();
		}
	}
}

//----------------------------------------------------------
BOOL	CPeaksPreviewHelper::Fix(BOOL bFix)
{
	GraphLayer	gly = Project.ActiveLayer();
	if( gly.IsValid() )
	{
		Collection<GraphObject>	coll;
		if ( gly.GetSpecialGraphicObjectsCollection(coll, _NANO_PEAKS_REG_NAME) )
		{
			foreach( GraphObject gr in coll )
			{
				if ( !disable_go_move(gr, true, true, true, !bFix) )
					return FALSE;
			}
		}
	}
	
	return TRUE;
}

//------ Folger 04/25/08 IMPROVE_MODIFY_AND_DELETE_PEAKS_IN_NANOSIZER
int		CPeaksPreviewHelper::SetSelectable(bool bEnable)
{
	GraphLayer	gly = Project.ActiveLayer();
	if( gly.IsValid() )
	{
		Collection<GraphObject>	coll;
		if ( gly.GetSpecialGraphicObjectsCollection(coll, _NANO_PEAKS_REG_NAME) )
		{
			foreach( GraphObject gr in coll )
			{
				if ( !set_go_selectable(gr, bEnable) )
					return FALSE;
			}
		}
	}
	
	return TRUE;
}

bool	CPeaksPreviewHelper::GetPeakNames(vector<string> &vsNames)
{
	GraphLayer	gly = Project.ActiveLayer();
	if( gly.IsValid() )
	{
		Collection<GraphObject>	coll;
		if ( gly.GetSpecialGraphicObjectsCollection(coll, _NANO_PEAKS_REG_NAME) )
		{
			foreach( GraphObject gr in coll )
			{
				vsNames.Add(gr.GetName());
			}
		}
	}
	
	return TRUE;
}
//------ End IMPROVE_MODIFY_AND_DELETE_PEAKS_IN_NANOSIZER

//----------------------------------------------------------
/// Hong 12/26/08 v8.0991 IMPROVE_SPEED
/*
int		CPeaksPreviewHelper::Get(vector& vXCenter, vector& vYCenter, vector& vXWidth, vector& vYWidth)
{
	vXCenter.RemoveAll();
	vYCenter.RemoveAll();
	if( NULL != vXWidth )
		vXWidth.RemoveAll();
	
	if( NULL != vYWidth )
		vYWidth.RemoveAll();
	
	GraphLayer	gly = Project.ActiveLayer();
	if( gly.IsValid() )
	{
		Collection<GraphObject>	coll;
		if ( gly.GetSpecialGraphicObjectsCollection(coll, _NANO_PEAKS_REG_NAME) )
		{
			foreach( GraphObject gr in coll )
			{
				vXCenter.Add(gr.X);
				vYCenter.Add(gr.Y);
				if( NULL != vXWidth ) 
					vXWidth.Add(gr.DX);
				if( NULL != vYWidth )
					vYWidth.Add(gr.DY);
			}
		}
	}
	
	return vXCenter.GetSize(); 
}
*/
int		CPeaksPreviewHelper::Get(vector& vXCenter, vector& vYCenter, vector& vXWidth, vector& vYWidth)
{
	int			nSize = 0;
	GraphLayer	gly = Project.ActiveLayer();
	if( gly.IsValid() )
	{
		Collection<GraphObject>	coll;
		if ( gly.GetSpecialGraphicObjectsCollection(coll, _NANO_PEAKS_REG_NAME) )
		{
			nSize = coll.Count();
			vXCenter.SetSize(nSize);
			vYCenter.SetSize(nSize);
			if( NULL != vXWidth )
				vXWidth.SetSize(nSize);			
			if( NULL != vYWidth )
				vYWidth.SetSize(nSize);
			int					nIndex = 0;
			foreach( GraphObject gr in coll )
			{
				vXCenter[nIndex] = gr.X;
				vYCenter[nIndex] = gr.Y;
				if( NULL != vXWidth ) 
					vXWidth[nIndex] = gr.DX;
				if( NULL != vYWidth )
					vYWidth[nIndex] = gr.DY;
				
				nIndex++;
			}
		}
	}
	
	if ( vXCenter.GetSize() > nSize )
	{
		vXCenter.SetSize(nSize);
		vYCenter.SetSize(nSize);
		if( NULL != vXWidth )
			vXWidth.SetSize(nSize);			
		if( NULL != vYWidth )
			vYWidth.SetSize(nSize);
	}
	
	return vXCenter.GetSize();
}
/// end IMPROVE_SPEED

//----------------------------------------------------------
BOOL	CPeaksPreviewHelper::Set(vector& vXCenter, vector& vYCenter, vector& vXWidth, vector& vYWidth)
{
	int nCount = vXCenter.GetSize();
	if( nCount != vYCenter.GetSize() ||  nCount != vXWidth.GetSize() || nCount != vYWidth.GetSize() )
		return FALSE;
	
	Reset();
	Tree trSettings;
	GetROIPeakGraphicObjectOptionalSettings(trSettings);
	for( int ii = 0; ii < nCount; ii++ )
	{
		GetPeakGraphicObjectSettings(trSettings, vXCenter[ii], vYCenter[ii], vXWidth[ii], vYWidth[ii], FALSE);
		string strName = get_shape_control_indexed_name(_NANO_PEAKS_REG_NAME, ii + 1);
		ShapeControl sc(GetLayer(), strName);
		sc.Create(GetLayer(), _NANO_PEAKS_REG_NAME, ii + 1, trSettings, GROT_ELLIPSE, false, false, false);
	}
	
	return TRUE;
}

//----------------------------------------------------------
int		CPeaksPreviewHelper::GetCount()
{
	GraphLayer gl = GetLayer();
	if( !gl )
		return -1;
	
	Collection<GraphObject>	coll;
	gl.GetSpecialGraphicObjectsCollection(coll, _NANO_PEAKS_REG_NAME);
	return coll.Count();
}

//----------------------------------------------------------
BOOL	CPeaksPreviewHelper::Add(double dX, double dY, double dXWidth, double dYWidth)
{
	GraphLayer gl = GetLayer();
	if( !gl )
		return FALSE;
	
	Tree trSettings;
	GetROIPeakGraphicObjectOptionalSettings(trSettings);
	GetPeakGraphicObjectSettings(trSettings, dX, dY, dXWidth, dYWidth, FALSE);

	// need to find unique name
	// first try index equal to collection size + 1, and then increment it, until found
	// this will be effecient most of the time
	int nIndex = GetCount() + 1;
	while( TRUE )
	{
		string strName = get_shape_control_indexed_name(_NANO_PEAKS_REG_NAME, nIndex);
		ShapeControl sc(GetLayer(), strName);
		if( !sc.IsValid() )
		{
			sc.Create(gl, _NANO_PEAKS_REG_NAME, nIndex, trSettings, GROT_ELLIPSE, false, false, false);
			break;
		}
		nIndex++;
	}
	
	return TRUE;
}

BOOL	CPeaksPreviewHelper::RemoveSelected()
{
	GraphObject gr;
	gr = Selection.Objects();
	if( gr )
	{
		gr.Destroy();
		return TRUE;
	}
	
	return FALSE;
}
///End CP_ASK_MOVE_CPEAKSPREVIEWHELPER_FROM_SPFM_UTILS
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
/////////////////   begin GraphObjTool    //////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////

///--------------------- Sophy 9/13/2008 GRAPH_OBJ_TOOL_BASE_CLASS
#define	GRAPH_TOOL_SETTINGS		"GraphToolSettings"
#define GRAPH_TOOL_CLASS_INFO	"GraphToolClassInfo"
//GraphObjTool::GraphObjTool(LPCSTR lpcszMainObjName)
//{
	//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);
//}
//
////---- 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);
	//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 
//BOOL GraphObjTool::Init()
//{
	//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
//
	//return true;
//}
//
////---- CPY 9/27/08 CENTRALIZE_ADD_RECT_FOR_ALL_TOOLS
//bool GraphObjTool::Attach(LPCSTR lpcszMainObjName)
//{
	//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);
//}
//
//void GraphObjTool::OnEvent(int nEvent, int nMsg)
//{
	//switch(nEvent)
	//{
	//case OE_MOVING:
	//case OE_RESIZING:
		//OnMoving();
		//break;
	//case OE_MOVE:
	//case OE_RESIZE:
		//OnMove();
		//break;
	///// Fisher 7/20/09 QA80-13975 HANDLE_RESCALE_EVENT_FOR_GRAPH_OBJ_TOOL
	//case OE_SCALE_CHANGE:
		//OnRescale();
		//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:
		//switch(nMsg)
		//{
//#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_		
		//case GOT_BTN_CLOSE:
			//DestroyInternal();
			//break;
		//}
	//default:
		////out_int("other even = ", nEvent);
	//}
//}
////----
//
//bool GraphObjTool::connectToObj(LPCSTR lpcszMainObjName)
//{
	//if( Attach(lpcszMainObjName) )
		//return readClassInfo();
	//
	//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;
//}
//void GraphObjTool::AddNewLine(string& str, string strNew)
//{
	//if(!str.IsEmpty())
		//str += "\r\n";
	//
	//str += strNew;
//}
//
////-----
//
/////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);", m_go.GetName());
		//LT_execute(strScript);
	//}
//}
//
//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;
//}
//
//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 )
//{
	//return tree_get_binary_storage( tr, m_go, GRAPH_TOOL_SETTINGS );
//}
////----- 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 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);
	//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;
//}
//
/////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);
			//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);
			/////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;
	////----
//
//}
//
////------ 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);
//*/
//BOOL GraphObjCurveTool::GetData()
//{
	//ASSERT(IsValidGrObj());
	//if(!m_go) return false; // release level checking		
	//if(!find_intersect_dataplot(m_go, m_dp, m_i1, m_i2))
	//{
		//m_i1 = m_i2 = -1;
		//return false;
	//}
	//m_dp.GetDataPoint(m_i1, &m_x1, NULL);
	//m_dp.GetDataPoint(m_i2, &m_x2, NULL);
	//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);
	//return find_intersect_dataplot(m_go, m_dp, vX, vY, true, dwCtrl);
	/////end DATAPLOT_GET_DATAPOINTS_NEED_TO_SKIP_MASKED_DATA
//}
///// end CURVE_STATS_QUICK_TOOL_MUST_BE_SMARTER
//
//
/////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);
	//
	///////----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;
//}
//
////---- 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;
//}
//
/////Sophy 1/5/2010 QA80-14904-S1 CLEAN_CODE_FOR_ROI_TOOLS
////virtual
//bool	GraphObjCurveTool::CheckAttachObjs()
//{
	//CreateAdvancedButtons(GetXFName());
	//return true;
//}
//
////virtual
//bool	GraphObjCurveTool::DoContext()
//{
	//POINT pt;
	//GetCursorPos(&pt);
	//
	//uint nCurItemPos = 0;
	//Menu pm;
	//pm.Add(STR_DO_OUTPUT, GOT_BTN_OUTPUT); nCurItemPos++;
	//pm.Add(NULL, 0, MF_SEPARATOR); nCurItemPos++;
	//AddPlots(pm, nCurItemPos);
	//pm.Add(STR_EXPAND_AREA, GOT_BTN_EXPAND); nCurItemPos++;
	//UpdateContextMenu(pm, nCurItemPos);
	//pm.Add(STR_DO_EDIT, GOT_BTN_EDIT); nCurItemPos++;
	//
	//int nCmdID;
	//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);
	//if ( nCmdID != 0 )
	//{
		//DWORD dwHigher = GOT_BTN_FIXED_MASK & nCmdID;
		//if ( 0 == dwHigher )
		//{
			//switch(nCmdID)
			//{
			//case GOT_BTN_OUTPUT:
				//DoOutput();
				//break;
				//
			//case GOT_BTN_EDIT:
				//DoEdit();
				//break;
				//
			//case GOT_BTN_EXPAND:
				//DoExpand();
				//break;
				//
			//case GOT_BTN_NLFIT:
				//DoNLFit();
				//break;
				//
			//case GOT_BTN_FINDXY:
				//DoFindXY();
				//break;
				//
			//default:
				//ASSERT(false);
				//break;
			//}
		//}
		//else
		//{
			//int	nIndex = (GOT_BTN_FLEX_MASK & nCmdID) - 1;
			//switch(dwHigher)
			//{
			//case GOT_BTN_PLOTS:
				//SetPlot(nIndex);
				//break;
			//case GOT_BTN_FUNCTION:
				//SetFunction(nIndex);
				//break;
			//default:
				//ASSERT(false);
				//break;
			//}
			//OnMove(); //update result
		//}
	//}
	//return true;
//}
//
//bool	GraphObjCurveTool::DoExpand()
//{
	//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);
	//if ( dp )
	//{
		//XYRange xyRange;
		//vector vX, vY;
		//dp.GetDataRange(xyRange);
		//xyRange.GetData(vY, vX);
		//double dMinX, dMaxX, dMinY, dMaxY;
		//vX.GetMinMax(dMinX, dMaxX);
		//vY.GetMinMax(dMinY, dMaxY);
		//
		//int nWidth = (dMaxX - dMinX);
		//int nHeight = dMaxY - dMinY;
		//m_gl.X.From = dMinX - nWidth * 0.08;
		//m_gl.X.To = dMaxX + nWidth * 0.08;
		//m_gl.Y.From = dMinY - nHeight * 0.08;
		//m_gl.Y.To = dMaxY + nHeight * 0.08;
		//
		//m_go.Left = dMinX;
		//m_go.Width = nWidth;
		//m_go.Top = dMaxY;
		//m_go.Height = nHeight;
		//
		//int nLeft, nTop, nRight, nBottom;
		//m_gl.WorldToPage(nLeft, nTop, dMinX, dMaxY);
		//m_gl.WorldToPage(nRight, nBottom, dMaxX, dMinY);
		//m_go.Left = nLeft - 1;  //one pixel margin as to include points on the edge.
		//m_go.Top = nTop - 1;
		//m_go.Width = (nRight - nLeft) + 2;
		//m_go.Height = (nTop - nBottom) + 2;
		//graphobjtool_events(*this, OE_RESIZE);
	//}
//
	//return true;
//}
//
//int		GraphObjCurveTool::AddPlots(Menu& pm, uint& nPosition)
//{
	//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 subMenu;
	//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;
	//}
	//
	//vector<string>	vsItems(0);
	//vector<int>		vnCmdIDs(0);
	//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();
				//trInfo.curPlotIndex.nVal = nCurPlotIndex;
				//tree_put_binary_storage(trInfo, m_go, ATTACHED_GRAPH_OBJECTS_INFO);
			//}
			//
			//string strName;
			//dp.GetRangeString(strName, NTYPE_SHORT_NAME_ONLY | NTYPE_BOOKSHEET_XY_RANGE | NTYPE_ADD_ROW_RANGE);
			//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 )
	//{
		//for ( int iItem = 0; iItem < vsItems.GetSize(); iItem++ )
		//{
			//DWORD dwFlag = MF_STRING;
			//if ( vnCmdIDs[iItem] == (GOT_BTN_PLOTS | (nCurPlotIndex + 1)) ) //current plot
				//dwFlag |= MF_CHECKED;
				//
			//subMenu.Add(vsItems[iItem], vnCmdIDs[iItem], dwFlag);
		//}
	//}
	//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;
//}
//
//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;
//}
//
//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 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);
	//trFormat.Root.Fill.Color.nVal = trGUI.rectcolor.nVal;
	//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, 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 )
	//{
		//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_copy_values(trGUI, tr);
			//trGUI.Replace(tr);
			//SetGUITree(trGUI); //should save GUI tree after handler updated for later use.
			//*pnXFEvtHandlerState = 1;
		//}
	//}
//}
/////end EVT_HANDLER_IN_TREENODE_INVALID_WHEN_RESTART_ORIGIN
//
//bool GraphObjCurveTool::SetResultsTree(const TreeNode& trResults)
//{
	//Tree tr;
	//GetTree(tr);
	//if(trResults)
		/////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()");
	//}
	//
	//if(bAppendWks)
	//{
		//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);
	//}
	//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);
		//int nDecimalDigits;
		//_LT_Obj
		//{
			//nDecimalDigits = system.NUMERIC.NUMDECDIGITS;
		//}
		//string strDoubleFormat;
		//strDoubleFormat.Format("%%.%ldlf", nDecimalDigits);
		//tree_to_str(trTemp, strOut, vnTableDisplayFormat, TREE2STR_SKIP_HIDDEN | TREE2STR_SIMPLE_TYPE_ONLY | dwCtrl, strDoubleFormat);
		/////end DUMP_RESULT_WITH_DOUBLE_USE_GLOBAL_DECIMAL_DIGIT_SETTINGS
		//if(bToScript)
		//{
			//LT_execute("type -a");
			//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)
//{
		//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);
		//
		//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
	

/// ------
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
/////////////////end/////GraphObjCurveTool//////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////

/// Iris 2/09/2010 FIX_COMPILE_ERR_WHEN_INCLUDE_GROBJUTILS_H_FILE
// if include grobj_utils.h file, compile error show, said cannot find the function body of RemoveAll
// so moved this function from grobj_utils.h to grobj_utils.c
bool ShapeControlListEx::Init(GraphLayer &gl, LPCSTR lpcszNameBase, double dxCenter, double dyCenter)
{
	if(!gl)
		return false;

	RemoveAll();
	m_layParent = gl;
	m_nCount = 0;
	m_lpcszNameBase = lpcszNameBase;
	m_dxCenter = dxCenter;
	m_dyCenter = dyCenter;
	return true;
}
///End FIX_COMPILE_ERR_WHEN_INCLUDE_GROBJUTILS_H_FILE

bool ShapeControlListEx::GetMember(ShapeControl& sc, int nIndex)
{
	if(!IsValid())
		return false;
	string strName = m_ObjNames[nIndex];
	ShapeControl scTemp(m_layParent, strName);
	if(!scTemp.IsValid())	
		return false;
	sc = scTemp;
	return true;
}

bool ShapeControlListEx::RemoveAll()
{
	if(!IsValid())
		return false;
	m_ObjNames.RemoveAll();
	m_ObjTypes.RemoveAll();
	m_nCount = 0;
	m_dxCenter = 0.0;
	m_dyCenter = 0.0;
	return true;
}

bool ShapeControlListEx::RemoveAt(int nIndex)
{
	if(!IsValid())
		return false;
	m_ObjNames.RemoveAt(nIndex);
	m_ObjTypes.RemoveAt(nIndex);
	--m_nCount;
	return true;
}

bool ShapeControlListEx::Remove(GraphObject& go)
{
	if(!IsValid())
		return false;
	return true;
}

bool ShapeControlListEx::Remove(string& strName)
{	
	if(!IsValid())
		return false;
	return true;
}

bool ShapeControlListEx::Add(int nObjType, TreeNode& trSettings)
{
	ShapeControl sc;
	BOOL bLine, bTitle, bLabel;
	bLine = true;
	bTitle = true;
	bLabel = false;
	if(sc.Create( m_layParent, m_lpcszNameBase, m_nCount++, trSettings, nObjType, bLine, bTitle, bLabel, ATTACH_TO_LAYER))
	{
        m_ObjNames.Add(sc.GetMainObjName());
		m_ObjTypes.Add(nObjType);
		ASSERT(m_ObjNames.GetSize() == m_nCount);
		return true;
	}
	
	return false;
}

bool ShapeControlListEx::Add(GraphObject& go)
{
	if(!go)
		return false;

	m_ObjNames.Add(go.GetName());
	int nObjType;
	go.GetObjectType(&nObjType);
	m_ObjTypes.Add(nObjType);
	++m_nCount;
	ASSERT(m_nCount == m_ObjTypes.GetSize());
	return true;
}

bool ShapeControlListEx::OnMove(double dx, double dy, int nUnitType)
{
	for(int ii = 0; ii<m_nCount; ++ii)
	{
		ShapeControl sc;
		if(GetMember(sc, ii))
		{
			double dXCenter, dYCenter, dLeft, dRight, dTop, dBottom;
			sc.GetPosition(dXCenter, dYCenter, dLeft, dRight, dTop, dBottom);
			sc.MoveTo(dLeft+dx, dRight+dx, dTop+dy, dBottom+dy, nUnitType);
		}
	}
	return true;
}

bool ShapeControlListEx::SetPosition(vector& vxLeft, vector& vxRight, vector& vyTop, vector& vyBottom, int nUnitType, vector<uint>&vnIndex)
{
	return true;
}

bool ShapeControlListEx::GetPosition(vector& vxCenter, vector& vyCenter, vector& vxLeft, vector& vxRight, vector& vyTop, vector& vyBottom,  vector<uint>&vnIndex)
{
	return true;
}

bool ShapeControlListEx::SaveToTree(TreeNode& tr)
{
	return true;
}


/// YuI 09/16/08 QA70-12204 POSITION_CONTROL_FOR_CONNECT_TO
static int _get_complement_tethering_point(int nTetheringPoint, RECT rectBound, int& nX, int& nY)
{
	switch( nTetheringPoint )
	{
	case CTP_LEFT_BOTTOM:
		nX = rectBound.left;
		nY = rectBound.bottom;
		//---- CPY 9/24/08 FINE_ADJUSTMENT_ON_BUTTON_POSITIONS_AS_ATTACHED_GR
		//return CTP_RIGHT_TOP;
		return CTP_RIGHT_BOTTOM;
		//----
		
	case CTP_LEFT:
		nX = rectBound.left;
		nY = (rectBound.top + rectBound.bottom) / 2;
		return CTP_RIGHT;
		
	case CTP_LEFT_TOP:
		nX = rectBound.left;
		nY = rectBound.top;
		//---- CPY 9/24/08 FINE_ADJUSTMENT_ON_BUTTON_POSITIONS_AS_ATTACHED_GR
		//return CTP_RIGHT_BOTTOM;
		return CTP_RIGHT_TOP;
		//----
		
	case CTP_TOP:
		nX = (rectBound.left + rectBound.right) / 2;
		nY = rectBound.top;
		return CTP_BOTTOM;
		
	case CTP_RIGHT_TOP:
		nX = rectBound.right;
		nY = rectBound.top;
		//---- CPY 9/24/08 FINE_ADJUSTMENT_ON_BUTTON_POSITIONS_AS_ATTACHED_GR
		//return CTP_LEFT_BOTTOM;
		return CTP_LEFT_TOP;
		//----
		
	case CTP_RIGHT:
		nX = rectBound.right;
		nY = (rectBound.top + rectBound.bottom) / 2;
		return CTP_LEFT;
		
	case CTP_RIGHT_BOTTOM:
		nX = rectBound.right;
		nY = rectBound.bottom;
		//---- CPY 9/24/08 FINE_ADJUSTMENT_ON_BUTTON_POSITIONS_AS_ATTACHED_GR
		//return CTP_LEFT_TOP;
		return CTP_LEFT_BOTTOM;
		//----
		
	case CTP_BOTTOM:
		nX = (rectBound.left + rectBound.right) / 2;
		nY = rectBound.bottom;
		return CTP_TOP;
		
	///Sophy 1/4/2010 QA80-14904-S1 SUPPORT_FLEXIBLE_ATTACHED_GROBJ_FOR_ROI_TOOLS
	case CTP_INNER_LEFT_TOP:
		nX = rectBound.left;
		nY = rectBound.top;
		return CTP_INNER_RIGHT_BOTTOM;
	case CTP_INNER_RIGHT_TOP:
		nX = rectBound.right;
		nY = rectBound.top;
		return CTP_INNER_LEFT_BOTTOM;
	case CTP_INNER_LEFT_BOTTOM:
		nX = rectBound.left;
		nY = rectBound.bottom;
		return CTP_INNER_RIGHT_TOP;
	case CTP_INNER_RIGHT_BOTTOM:
		nX = rectBound.right;
		nY = rectBound.bottom;
		return CTP_INNER_LEFT_TOP;
	///end SUPPORT_FLEXIBLE_ATTACHED_GROBJ_FOR_ROI_TOOLS
	}
	
	//ASSERT(false); /// Iris 12/11/2009 CTP_AUTO cause assert failed, so comment out
	
	// CTP_AUTO means center
	nX = (rectBound.left + rectBound.right) / 2;
	nY = (rectBound.top + rectBound.bottom) / 2;
	return CTP_AUTO;
}

///Sophy 1/5/2010 QA80-14904-S1 CLEAN_CODE_FOR_ROI_TOOLS
static bool _update_gaps(GraphObject& gr, int& nXGap, int& nYGap, POGRGAP pGapCtrl = NULL)
{
	if ( !gr || NULL == pGapCtrl )
		return false;
	
	//int nXCtrl = dwCtrl & CJ_VIEW_X_GAP_MASK;
	//switch(nXCtrl)
	//{
	//case CJ_VIEW_X_GAP_N:
		//nXGap = gr.Width * 0.2;
		//break;
		//
	//case CJ_VIEW_X_GAP_L:
		//nXGap = gr.Width;
		//break;
		//
	//case CJ_VIEW_X_GAP_XL:
		//nXGap = gr.Width * 2;
		//break;
		//
	//case CJ_VIEW_X_GAP_XXL:
		//nXGap = gr.Width * 3;
		//break;
		//
	//case CJ_VIEW_X_GAP_XXXL:
		//nXGap = gr.Width * 4;
		//break;
		//
	//default:
		//break;
	//}
	//
	//int nYCtrl = dwCtrl & CJ_VIEW_Y_GAP_MASK;
	//switch(nYCtrl)
	//{
	//case CJ_VIEW_Y_GAP_N:
		//nYGap = gr.Height * 0.2;
		//break;
		//
	//case CJ_VIEW_Y_GAP_L:
		//nYGap = gr.Height * 1.4;
		//break;
		//
	//case CJ_VIEW_Y_GAP_XL:
		//nYGap = gr.Height * 2.8;
		//break;
		//
	//case CJ_VIEW_Y_GAP_XXL:
		//nYGap = gr.Height * 4.2;
		//break;
		//
	//case CJ_VIEW_Y_GAP_XXXL:
		//nYGap = gr.Height * 5.6;
		//break;
		//
	//default:
		//break;
	//}
	nXGap = pGapCtrl->xGap * gr.Width;
	nYGap = pGapCtrl->yGap * gr.Height;
	return true;
}
///end CLEAN_CODE_FOR_ROI_TOOLS
///Sophy 12/30/2009 QA80-14904-S1 SUPPORT_FLEXIBLE_ATTACHED_GROBJ_FOR_ROI_TOOLS
//static bool _jastify_graphic_object(GraphObject& gr, int nTetheringPoint, int nX, int nY)
static bool _jastify_graphic_object(GraphObject& gr, int nTetheringPoint, int nX, int nY, POGRGAP pGapCtrl = NULL)
///end SUPPORT_FLEXIBLE_ATTACHED_GROBJ_FOR_ROI_TOOLS
{	
	///Sophy 1/5/2010 QA80-14904-S1 CLEAN_CODE_FOR_ROI_TOOLS
	int nXGap = 0, nYGap = 0;
	_update_gaps(gr, nXGap, nYGap, pGapCtrl);
	///end CLEAN_CODE_FOR_ROI_TOOLS
	gr.Invalidate();
	
	switch( nTetheringPoint )
	{
	case CTP_AUTO:
		gr.Left = nX - gr.Width / 2;
		gr.Top = nY - gr.Height / 2;
		break;
		
	case CTP_LEFT_BOTTOM:
		//---- CPY 9/24/08 FINE_ADJUSTMENT_ON_BUTTON_POSITIONS_AS_ATTACHED_GR
		//gr.Left = nX;
		gr.Left = nX + nXGap;
		//----
		gr.Top = nY - gr.Height - nYGap;
		break;
		
	case CTP_LEFT:
		gr.Left = nX;
		gr.Top = nY - gr.Height / 2;
		break;
		
	case CTP_LEFT_TOP:
		//---- CPY 9/24/08 FINE_ADJUSTMENT_ON_BUTTON_POSITIONS_AS_ATTACHED_GR
		//gr.Left = nX;
		gr.Left = nX + nXGap;
		//----
		gr.Top = nY + nYGap;
		break;
		
	case CTP_TOP:
		gr.Left = nX - gr.Width / 2;
		gr.Top = nY - gr.Height; //nY; CPY 9/23/08 need to shift up to be inside rect, temp solution
		break;
		
	case CTP_RIGHT_TOP:
		gr.Left = nX - gr.Width;
		gr.Top = nY;
		break;
		
	case CTP_RIGHT:
		gr.Left = nX - gr.Width;
		gr.Top = nY - gr.Height / 2;
		break;
		
	case CTP_RIGHT_BOTTOM:
		gr.Left = nX - gr.Width;
		gr.Top = nY - gr.Height;
		break;
		
	case CTP_BOTTOM:
		gr.Left = nX - gr.Width / 2;
		gr.Top = nY - gr.Height;
		break;
	///Sophy 1/4/2010 QA80-14904-S1 SUPPORT_FLEXIBLE_ATTACHED_GROBJ_FOR_ROI_TOOLS
	case CTP_INNER_LEFT_TOP:
		gr.Left = nX - gr.Width;
		gr.Top = nY - gr.Height;
		break;
	case CTP_INNER_RIGHT_TOP:
		gr.Left = nX;
		gr.Top = nY - gr.Height;
		break;
	case CTP_INNER_LEFT_BOTTOM:
		gr.Left = nX - gr.Width - nXGap;
		gr.Top = nY + nYGap;
		break;
	case CTP_INNER_RIGHT_BOTTOM:
		gr.Left = nX;
		gr.Top = nY;
		break;
	///end SUPPORT_FLEXIBLE_ATTACHED_GROBJ_FOR_ROI_TOOLS
	}
	
	return true; 
}

///Sophy 12/30/2009 QA80-14904-S1 SUPPORT_FLEXIBLE_ATTACHED_GROBJ_FOR_ROI_TOOLS
//bool	connect_justify(GraphObject& grTarget, GraphObject& gr, int nTargetTetheringPoint)
bool	connect_justify(GraphObject& grTarget, GraphObject& gr, int nTargetTetheringPoint, POGRGAP pGapCtrl) //NULL
///end SUPPORT_FLEXIBLE_ATTACHED_GROBJ_FOR_ROI_TOOLS
{
	if( !grTarget || !gr )
		return false;
	
	int nTetheringX = 0;
	int nTetheringY = 0;
	RECT rectTargetBound;
	rectTargetBound.left = grTarget.Left;
	rectTargetBound.top = grTarget.Top;
	rectTargetBound.bottom = grTarget.Top + grTarget.Height;
	rectTargetBound.right = grTarget.Left + grTarget.Width;;

	int nTetheringPoint = _get_complement_tethering_point(nTargetTetheringPoint, rectTargetBound, nTetheringX, nTetheringY);
	
	// first do justification
	if( !_jastify_graphic_object(gr, nTetheringPoint, nTetheringX, nTetheringY, pGapCtrl) )
		return false;
	
	// then do invisible one-side rigid connection
	// also restrict its movement
	RECT rectConfine = {-300, -300, 300, 300};
	///------ Folger 01/23/10 QA81-14903 FIT_CURVE_LINE_IN_QUICK_FIT_SHOULD_NOT_DRAW_EDGE_WHEN_SELECT_ROI
	//return gr.ConnectTo(grTarget, nTargetTetheringPoint, nTetheringPoint, FALSE, OCR_SITE2, &rectConfine); 
	return gr.ConnectTo(grTarget, nTargetTetheringPoint, nTetheringPoint, FALSE, OCR_SITE2 | OCR_CNTRL_NOT_DRAW_EDGE_IF_UNSELECTABLE, &rectConfine);
	///------ End FIT_CURVE_LINE_IN_QUICK_FIT_SHOULD_NOT_DRAW_EDGE_WHEN_SELECT_ROI
}
/// end POSITION_CONTROL_FOR_CONNECT_TO



/// end	GRAPH_OBJ_CURVE_TOOL


//-------- CPY 10/17/08 MAKE_CONTROL_RECT_IN_TEMPLATE_TO_HAVE_NEW_SEL_BIT
#pragma labtalk(2) 
// this function allows LT script to control some gr obj
// for example:
// run -oc {set_gr_sel_before_data Rect}
void set_gr_sel_before_data(string strName)
{
	GraphLayer gl = Project.ActiveLayer();
	if(gl)
	{
		GraphObject go = gl.GraphObjects(strName);
		if(go)
		{
			set_go_hittest_before_data(go);
			return;
		}
		printf("%s not found\n");
		return;
	}
	printf("not graph layer\n");
}
//--------

///Sandy 2008-12-23 move in GraphObjCurveTool class as member function
//static void _get_go_bounding_box_info(GraphObject& go, string& str)
//{
	//if(go)
	//{
		//GraphLayer gl;
		//go.GetParent(gl);
		//if(gl)
		//{
			//FRECT frect;
			//go.GetTempBoundingBox(&frect);
			//double x1 = gl.X.From;
			//double x2 = 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);
		//}
	//}
//}

	

