/*
================================ COPYRIGHT ================================
The contents of this file are subject to the VTech Informations Ltd. License
of VT-OS Ver. 1.1 operating system (the "License"); you may not use this 
file except in compliance with the License.  

Software distributed under the License is distributed on an "AS IS" basis, 
WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License 
for the specific language governing rights and limitations under the License.
  
The Original Code is VT-OS Ver. 1.1 Operating System, released 
on October 1st, 1999
	
The Initial Developer of the Original Code is VTech Informations Ltd.  All 
codes are Copyright (C) VTech Informations Ltd. 1999.  All Rights Reserved.
===========================================================================
*/

/*
===========================================================================
File        :   field.c
Author(s)   :   Henry Fok, David Lo
Company     :   VTech Informations Ltd.
Project     :   Helio 
Date:	    :   October 1st, 1999
Purpose:	:   Field object functions
Revision    :   1.1
Note        :   None
===========================================================================
*/              


#include "stdafx.h"
#include "uidef.h"
#include "uifunc.h"

//#define DEBUG
//#define DEBUG_GF
//#define DEBUG_KEY
//#define DEBUG_TAB
//#define DEBUG_KIT


/********************************************************
* Function:	FieldGetTotalNumOfLines
* Purpose:     to get the total number of lines of a field object
* Scope:		Application
* Input:       field_id 	    DBID of the spceified field object
total_num_lines the total number of lines of a field object
* Output:		None
* Return:		Error code
UI_ERR_RES_NOT_FOUND;
* Comment:		None
*********************************************************/
Err FieldGetTotalNumOfLines(ObjectID field_id, WORD *total_num_lines)
{
    Field *addr;
    BYTE object_type;
	
    if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE) return ERR_UI_RES_NOT_FOUND;
	*total_num_lines = addr->field_total_num_lines;
    return TRUE;
}
/********************************************************
* Function:	FieldGetNumOfLinesDisplayed
* Purpose:     to get the number of lines that are displayed the total number of lines of a field object
* Scope:		Application
* Input:       feidl_id 	        DBID of the spceified field object
num_lines_displayed the number of lines that are displayed
on the field object
* Output:		None
* Return:		Error code
UI_ERR_RES_NOT_FOUND;
* Comment:		None
*********************************************************/
Err FieldGetNumOfLinesDisplayed(ObjectID field_id, WORD *num_lines_displayed)
{
    Field *addr;
    BYTE object_type;
	
    if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE) return ERR_UI_RES_NOT_FOUND;
	*num_lines_displayed = addr->field_num_lines_displayed;
    return TRUE;
}

/********************************************************
* Function:	FieldGetMaxNumLinesDisplay
* Purpose:     to get the maximum number of lines that can be displayed
* Scope:		Application
* Input:       feidl_id 	        DBID of the spceified field object
num_lines			the max number of lines that can be displayed
* Output:		None
* Return:		Error code
UI_ERR_RES_NOT_FOUND;
* Comment:		None
*********************************************************/
Err FieldGetMaxNumLinesDisplay(ObjectID field_id, WORD *num_lines)
{
    Field *addr;
    BYTE object_type;
	
    if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE) return ERR_UI_RES_NOT_FOUND;
	*num_lines = addr->bounds.height / (FONT_HEIGHT[addr->field_font_id] + SPACE_LINE);
    return TRUE;
}

/********************************************************
* Function:	FieldGetTopLineNum
* Purpose:     to get the top line number of the field object
* Scope:		Application
* Input:       field_id 	        DBID of the spceified field object
line_num            the line number of the top line of
the display of the field object
* Output:		None
* Return:		Error code
UI_ERR_RES_NOT_FOUND;
* Comment:		None
*********************************************************/
Err FieldGetTopLineNum(ObjectID field_id, WORD *line_num)
{
    Field *addr;
    BYTE object_type;
	
    if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE) return ERR_UI_RES_NOT_FOUND;
    *line_num = addr->field_top_line_num;
    return TRUE;
}
/********************************************************
* Function:	FieldDirty
* Purpose:     to get the dirty bit of a field object
* Scope:		Application
* Input:       field_id 	        DBID of the spceified field object
* Output:		dirty               Pointer to Boolean dirty
* Return:		Error code
UI_ERR_RES_NOT_FOUND;
* Comment:		None
*********************************************************/
Err FieldDirty(ObjectID field_id, BOOLEAN *dirty)
{
    Field *addr;
    BYTE object_type;
	
    if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE) return ERR_UI_RES_NOT_FOUND;
    *dirty = addr->field_attr.field_dirty;
    return TRUE;
}
/********************************************************
* Function:	FieldEraseField
* Purpose:     to erase the particular field object
* Scope:		Application
* Input:       field_id 	        DBID of the spceified field object
* Output:		None
* Return:		Error code
UI_ERR_RES_NOT_FOUND;
* Comment:		None
*********************************************************/
Err FieldEraseField(ObjectID field_id)
{
    Field *addr;
    BYTE object_type;
	
    if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE) return ERR_UI_RES_NOT_FOUND;
    if (addr->field_attr.field_drawn)
    {
		if (addr->identification.table_related != 0xFFFF)
			LcdEraseRegion(&(addr->screen_bounds));
		else LcdEraseRegion(&(addr->bounds));
		addr->field_attr.field_drawn = FALSE;
    }
    return TRUE;
}
/********************************************************
* Function:	FieldGetFieldBounds
* Purpose:     to get the bounds of the field object
* Scope:		Application
* Input:       field_id 	        DBID of the spceified field object
* Output:		bounds              Pointer to bounds of field object
* Return:		Error code
UI_ERR_RES_NOT_FOUND;
* Comment:		None
*********************************************************/
Err FieldGetFieldBounds(ObjectID field_id, ObjectBounds *bounds)
{
    Field *addr;
    BYTE object_type;
	
    if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE) return ERR_UI_RES_NOT_FOUND;
    if (addr->identification.table_related != 0xFFFF)
		*bounds = addr->screen_bounds;
    else *bounds = addr->bounds;
    return TRUE;
}
/********************************************************
* Function:	FieldGetInsertPointPosition
* Purpose:     to get the insert point position of the
* Scope:		Application
* Input:       field_id 	        DBID of the spceified field object
* Output:		bounds              Pointer to bounds of field object
* Return:		Error code
UI_ERR_RES_NOT_FOUND;
* Comment:		None
*********************************************************/
Err FieldGetInsertPointPosition(ObjectID field_id, WORD *char_pos)
{
    Field *addr;
    BYTE object_type;
	
    if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE) return ERR_UI_RES_NOT_FOUND;
    if (addr->field_attr.field_insert_pt_visible)
		*char_pos = addr->field_insert_pt_char_pos;
    else *char_pos = -1;
    return TRUE;
}
/********************************************************
* Function:	FieldDeleteField
* Purpose:     to delete a field object from memory
* Scope:		Application
* Input:       field_id 	        DBID of the spceified field object
* Output:		None
* Return:		Error code
UI_ERR_RES_NOT_FOUND;
* Comment:		None
*********************************************************/
Err FieldDeleteField(ObjectID field_id)
{
	Field *addr;
	BYTE object_type;
	Err Error;
	
	if (UISearchForAddress(field_id,&object_type, (void**)&addr) == TRUE)
	{
        if (addr->field_string)
			qfree(addr->field_string);
        if (addr->field_lineinfo)
			qfree(addr->field_lineinfo);
		Error = UIDeleteLookupTableElement(field_id);
		if (Error !=TRUE) return Error;
		qfree(addr);
		return TRUE;
	}
	return ERR_UI_RES_NOT_FOUND;
}
/********************************************************
* Function:	FieldGetCurrentHighlightSelection
* Purpose:     to get the current highlight selection position
* Scope:		Application
* Input:       field_id 	        DBID of the spceified field object
* Output:      star_char_pos       Pointer to the start character position of selected
range of characters
end_char_pos        Pointer to the end-character position of selected
range of characters
* Return:		Error code
UI_ERR_RES_NOT_FOUND;
* Comment:		None
*********************************************************/
Err FieldGetCurrentHighlightedSelection(ObjectID field_id, WORD *star_char_pos,
                                        WORD *end_char_pos)
{
	Field *addr;
	BYTE object_type;
	
    if (UISearchForAddress(field_id,&object_type, (void**)&addr) != TRUE) return ERR_UI_RES_NOT_FOUND;
    if (addr->field_attr.field_highlight)
    {
		*star_char_pos = addr->field_highlight_start_char;
		*end_char_pos = addr->field_highlight_start_char + addr->field_highlight_length;
    }
    else
    {
		*star_char_pos = -1;
		*end_char_pos = -1;
    }
    return TRUE;
}
/********************************************************
* Function:	FieldScrollField
* Purpose:     to enable the insert pt in the correct position
* Scope:		Application
* Input:       field_id 	        DBID of the spceified field object
* Output:      None
* Return:		Error code
ERR_UI_RES_NOT_FOUND;
* Comment:		None
*********************************************************/
Err FieldScrollField(ObjectID field_id, WORD line_to_scroll)
{
	Field *addr;
	BYTE object_type;
    WORD line_number;
	
    if (UISearchForAddress(field_id,&object_type, (void**)&addr) != TRUE) return ERR_UI_RES_NOT_FOUND;
    line_number = addr->field_top_line_num + line_to_scroll;
    if ( 0 <= line_number &&
        (addr->field_total_num_lines - addr->field_num_lines_displayed) <= line_number)
		addr->field_top_line_num = line_number;
    else
    {
		if (line_to_scroll >0)
			addr->field_top_line_num = addr->field_total_num_lines -
			addr->field_num_lines_displayed;
		else
			addr->field_top_line_num = 0;
    }
    return TRUE;
}
/********************************************************
* Function:	FieldSendHeightChangeNotification
* Purpose:     to enable the insert pt in the correct position
* Scope:		Application
* Input:       field_id 	        DBID of the spceified field object
* Output:      None
* Return:		Error code
ERR_UI_RES_NOT_FOUND;
* Comment:		None
*********************************************************/
Err FieldSendHeightChangeNotification(ObjectID field_id)
{
	Field *addr;
	BYTE object_type;
	
    if (UISearchForAddress(field_id,&object_type, (void**)&addr) != TRUE) return ERR_UI_RES_NOT_FOUND;
	EvtAppendEvt(EVT_FIELD_HEIGHT, field_id, 0, 0, (void*)addr);
    return TRUE;
}
/********************************************************
* Function:	FieldSetBounds
* Purpose:     to set the object bounds of a field object
* Scope:		Application
* Input:       field_id 	        DBID of the spceified field object
bounds              bounds of the field object
* Output:      None
* Return:		Error code
ERR_UI_RES_NOT_FOUND;
* Comment:		None
*********************************************************/
Err FieldSetBounds(ObjectID field_id, ObjectBounds bounds)
{
	Field *addr;
	BYTE object_type;
	
    if (UISearchForAddress(field_id,&object_type, (void**)&addr) != TRUE) return ERR_UI_RES_NOT_FOUND;
    addr->bounds = bounds;
	if (addr->identification.table_related != 0xFFFF)
		TableUpdateObjectScreenBounds(addr->identification.table_related, field_id/*, USHORT row_num, USHORT col_num*/);
	StrAnalyzeLine(addr);
    return TRUE;
}
/********************************************************
* Function:	FieldSetFont
* Purpose:     to set the font of the field object
* Scope:		Application
* Input:       field_id 	        DBID of the spceified field object
font                font type for the field object
* Output:      None
* Return:		Error code
ERR_UI_RES_NOT_FOUND;
* Comment:		None
*********************************************************/
Err FieldSetFont(ObjectID field_id, BYTE font)
{
	Field *addr;
	BYTE object_type;
	
    if (UISearchForAddress(field_id,&object_type, (void**)&addr) != TRUE) return ERR_UI_RES_NOT_FOUND;
    addr->field_font_id = font;
	if (addr->identification.table_related != 0xFFFF)
		TableUpdateObjectScreenBounds(addr->identification.table_related, field_id/*, USHORT row_num, USHORT col_num*/);
	StrAnalyzeLine(addr);
    return TRUE;
}
/********************************************************
* Function:	FieldSetInsertPointOff
* Purpose:     to turn off the insert point of the field
* Scope:		Application
* Input:       field_id 	        DBID of the spceified field object
* Output:      None
* Return:		Error code
ERR_UI_RES_NOT_FOUND;
* Comment:		None
*********************************************************/
Err FieldSetInsertPointOff(ObjectID field_id)
{
	Field *addr;
	BYTE object_type;
	
    if (UISearchForAddress(field_id,&object_type, (void**)&addr) != TRUE) return ERR_UI_RES_NOT_FOUND;
    LcdEnableInsertPt(FALSE,0,0,0);
    addr->field_attr.field_insert_pt_visible = FALSE;
    return TRUE;
}
/********************************************************
* Function:	FieldSetInsertPointOn
* Purpose:     to turn on the insert point of the field
* Scope:		Application
* Input:       field_id 	        DBID of the spceified field object
* Output:      None
* Return:		Error code
ERR_UI_RES_NOT_FOUND;
* Comment:		None
*********************************************************/
Err FieldSetInsertPointOn(ObjectID field_id)
{
	Field *addr;
	BYTE object_type;
	
    if (UISearchForAddress(field_id,&object_type, (void**)&addr) != TRUE) return ERR_UI_RES_NOT_FOUND;
    LcdEnableInsertPt(TRUE,addr->field_insert_pt_x, addr->field_insert_pt_y, addr->field_font_id);
    addr->field_attr.field_insert_pt_visible = TRUE;
    addr->field_attr.field_highlight = FALSE;
    return TRUE;
}

/********************************************************
* Function:	FieldSetText
* Purpose:     to set the string of the field object
* Scope:		Application
* Input:       field_id 	        DBID of the spceified field object
string              Pointer to null-terminated string
* Output:      None
* Return:		Error code
ERR_UI_RES_NOT_FOUND;
* Comment:		None
*********************************************************/
Err FieldSetText(ObjectID field_id, BYTE *string)
{
	Field *addr;
	BYTE object_type;
    WORD temp_length, temp_length1;
	
#ifdef DEBUG_KIT
    printf("\n ====== In Field Set Text ======");
#endif
	
    if (UISearchForAddress(field_id, &object_type, (void**)&addr) != TRUE) return ERR_UI_RES_NOT_FOUND;
	
#ifdef DEBUG_KIT
    printf("\n Field Pointer A = %08x", addr);
    printf("\n Field Font Id = %ld", addr->field_font_id);
#endif
	
    temp_length = strlen(string);
	
#ifdef DEBUG_KIT
    printf("\n strlen = %ld", temp_length);
#endif
	
	
    if (temp_length > addr->field_max_chars)
        return ERR_UI_FIELD_OVER_MAX_NUM_CHARS;
	
#ifdef DEBUG_KIT
    printf("\n Field Pointer B = %08x", addr);
    printf("\n Field Font Id = %ld", addr->field_font_id);
#endif
	
	
    qfree(addr->field_string);
	
#ifdef DEBUG_KIT
    printf("\n Field Pointer C = %08x", addr);
    printf("\n Field Font Id = %ld", addr->field_font_id);
#endif
	
	
	temp_length1 = ((temp_length)/STEP_SIZE + 1) * STEP_SIZE;
	
#ifdef DEBUG_KIT
    printf("\n Field Pointer D = %08x", addr);
    printf("\n Field Font Id = %ld", addr->field_font_id);
#endif
	
	
    addr->field_string = (BYTE*)qmalloc(temp_length1*sizeof(BYTE));
	
#ifdef DEBUG_KIT
    printf("\n Field Pointer E = %08x", addr);
    printf("\n Field Font Id = %ld", addr->field_font_id);
#endif
	
	
    strcpy(addr->field_string, string);
	
#ifdef DEBUG_KIT
    printf("\n Field Pointer F = %08x", addr);
    printf("\n Field Font Id = %ld", addr->field_font_id);
#endif
	
	
    addr->field_current_num_chars = temp_length;
	
#ifdef DEBUG_KIT
    printf("\n Field Pointer G = %08x", addr);
    printf("\n Field Font Id = %ld", addr->field_font_id);
#endif
	
	
	if (addr->identification.table_related != 0xFFFF)
		TableUpdateObjectScreenBounds(addr->identification.table_related, field_id);
	
#ifdef DEBUG_KIT
    printf("\n Field Pointer H = %08x", addr);
    printf("\n Field Font Id = %ld", addr->field_font_id);
#endif
	
	
	
	StrAnalyzeLine(addr);
	
#ifdef DEBUG_KIT
    printf("\n Field Pointer I = %08x", addr);
    printf("\n Field Font Id = %ld", addr->field_font_id);
#endif
	
#ifdef DEBUG_KIT
    printf("\n ====== Out Field Set Text ======");
#endif
	
	
    return TRUE;
}
/********************************************************
* Function:	FieldGetAttribute
* Purpose:	Get the pointer of the field's attribute structure
* Scope:	Application
* Input:    field_id	DBID of the spceified field object
* Output:	field_attr	Pointer to the field's attribute
*						structure
* Return:	Error code
*			UI_ERR_RES_NOT_FOUND;
* Comment:	None
*********************************************************/
Err FieldGetAttribute(ObjectID field_id, FieldAttr *field_attr)
{
	Field *addr;
	BYTE object_type;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	*field_attr = addr->field_attr;
	return TRUE;
}
/********************************************************
* Function:	FieldGetFont
* Purpose:	Get the font of the field object
* Scope:	Application
* Input:    field_id	DBID of the spceified field object
* Output:	font_id		Return the font of the field object
* Return:	Error code
*			UI_ERR_RES_NOT_FOUND;
* Comment:	None
*********************************************************/
Err FieldGetFont(ObjectID field_id, BYTE *font_id)
{
	Field *addr;
	BYTE object_type;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	*font_id = addr->field_font_id;
	return TRUE;
}
/********************************************************
* Function:	FieldGetMaxNumChars
* Purpose:	Get the maximum numbers of char in the field object
* Scope:	Application
* Input:    field_id			DBID of the spceified field object
* Output:	max_num_of_chars	Maximum number of char in the field
*								object
* Return:	Error code
*			UI_ERR_RES_NOT_FOUND;
* Comment:	None
*********************************************************/
Err FieldGetMaxNumChars(ObjectID field_id, WORD *max_num_of_chars)
{
	Field *addr;
	BYTE object_type;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	*max_num_of_chars = addr->field_max_chars;
	return TRUE;
}
/********************************************************
* Function:	FieldGetTextPointer
* Purpose:	Get the text pointer of the specified field object
* Scope:	Application
* Input:    field_id		DBID of the spceified field object
* Output:	text_ptr
* Return:	Error code
*			UI_ERR_RES_NOT_FOUND;
* Comment:	None
*********************************************************/
Err FieldGetTextPointer(ObjectID field_id, BYTE **text_ptr)
{
	Field *addr;
	BYTE object_type;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	*text_ptr = ((BYTE *)addr->field_string);
	return TRUE;
}
/********************************************************
* Function:	FieldGetNumOfChars
* Purpose:	Get current number of char in the field object
* Scope:	Application
* Input:    field_id		DBID of the spceified field object
* Output:	num_chars		Number of char in the field object
* Return:	Error code
*			UI_ERR_RES_NOT_FOUND;
* Comment:	None
*********************************************************/
Err FieldGetNumOfChars(ObjectID field_id, WORD *num_chars)
{
	Field *addr;
	BYTE object_type;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	*num_chars = addr->field_current_num_chars;
	return TRUE;
}
/********************************************************
* Function:	FieldSetScrollbarAttribute
* Purpose:	Set or clear the attribute of field to indicate that there is a scrollbar or not
* Scope:	Application
* Input:    field_id		DBID of the spceified field object
*			has_scrollbar	to show whether it is on or not 
* Output:	None
* Return:	Error code
*			UI_ERR_RES_NOT_FOUND;
* Comment:	None
*********************************************************/
Err FieldSetScrollbarAttribute(ObjectID field_id, BOOLEAN has_scrollbar)
{
	Field *addr;
	BYTE object_type;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	addr->field_attr.field_scrollbar = has_scrollbar;
	return TRUE;
}
/********************************************************
* Function:	FieldGetScrollbarAttribute
* Purpose:	get the attribute of field to indicate that there is a scrollbar or not
* Scope:	Application
* Input:    field_id		DBID of the spceified field object
* Output:	has_scrollbar	Indicate the specified field object
*							has a scrollbar
* Return:	Error code
*			UI_ERR_RES_NOT_FOUND;
* Comment:	None
*********************************************************/
Err FieldGetScrollbarAttribute(ObjectID field_id, BOOLEAN *has_scrollbar)
{
	Field *addr;
	BYTE object_type;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	*has_scrollbar = addr->field_attr.field_scrollbar;
	return TRUE;
}

/********************************************************
* Function:	FieldSetAttribute
* Purpose:	Set the field's attributes
* Scope:	Application
* Input:    field_id	DBID of the spceified field object
* 			field_attr	Pointer to the field's attribute
*						structure
* Output:	None
* Return:	Error code
*			UI_ERR_RES_NOT_FOUND;
* Comment:	None
*********************************************************/
Err FieldSetAttribute(ObjectID field_id, FieldAttr input_field_attr)
{
	Field *addr;
	BYTE object_type;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	addr->field_attr = input_field_attr;
	return TRUE;
}
/********************************************************
* Function:	FieldSetDirty
* Purpose:	Set the dirty attribute of the specified field object
* Scope:	Application
* Input:    field_id		DBID of the spceified field object
*			field_dirty		Value of the dirty attribute
* Output:	None
* Return:	Error code
*			UI_ERR_RES_NOT_FOUND;
* Comment:	None
*********************************************************/
Err FieldSetDirty(ObjectID field_id, BOOLEAN field_dirty)
{
	Field *addr;
	BYTE object_type;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	addr->field_attr.field_dirty = field_dirty;
	return TRUE;
}
/********************************************************
* Function:	FieldSetInsertPointPositionByXY
* Purpose:	Set the Insert point position of a particular field
*			object
* Scope:	Application
* Input:    field_id		DBID of the spceified field object
*			insert_xcoord	x-coordinate of the insert point
*			insert_ycoord	y-coordinate of the insert point
* Output:	None
* Return:	Error code
*			UI_ERR_RES_NOT_FOUND;
* Comment:	None
*********************************************************/
Err FieldSetInsertPointPositionByXY(ObjectID field_id, SHORT insert_xcoord, SHORT insert_ycoord)
{
	Field *addr;
	BYTE object_type;
	WORD char_pos;
	SHORT new_xcoord, new_ycoord;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	StrAnalyzeLine(addr);
	StrGetInsertPtPos(addr,insert_xcoord,insert_ycoord,&char_pos,
		&new_xcoord,&new_ycoord);
	addr->field_insert_pt_x = new_xcoord;
	addr->field_insert_pt_y = new_ycoord;
	addr->field_insert_pt_char_pos = char_pos;
	return TRUE;
}
/********************************************************
* Function:	FieldSetInsertPointPositionByCharPos
* Purpose:	Set the Insert point position of a particular field
*			object
* Scope:	Application
* Input:    field_id		DBID of the spceified field object
*			char_pos		character position of character that insertion point locates
* Output:	None
* Return:	Error code
*			UI_ERR_RES_NOT_FOUND;
* Comment:	None
*********************************************************/
Err FieldSetInsertPointPositionByCharPos(ObjectID field_id, WORD char_pos)
{
	Field *addr;
	BYTE object_type;
	SHORT new_xcoord, new_ycoord;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	StrAnalyzeLine(addr);
	StrCharPosToXY(addr,char_pos,&new_xcoord,&new_ycoord);
	addr->field_insert_pt_x = new_xcoord;
	addr->field_insert_pt_y = new_ycoord;
	addr->field_insert_pt_char_pos = char_pos;
	return TRUE;
}
/********************************************************
* Function:	FieldSetTopLineNum
* Purpose:	Set the maximum numbers of char in the field object
* Scope:	Application
* Input:    field_id			DBID of the spceified field object
* Input:	top_line_num		TopLine Num
* Ouput:	None
* Return:	Error code
*			UI_ERR_RES_NOT_FOUND;
* Comment:	None
*********************************************************/
Err FieldSetTopLineNum(ObjectID field_id, WORD top_line_num)
{
	Field *addr;
	BYTE object_type;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	if (addr->field_top_line_num <0) 
		addr->field_top_line_num = 0;
	else if (addr->field_top_line_num > (addr->field_total_num_lines - 1))
		addr->field_top_line_num = (addr->field_total_num_lines - 1);
	else 
		addr->field_top_line_num = top_line_num;
	if (addr->identification.table_related != 0xFFFF)
		TableUpdateObjectScreenBounds(addr->identification.table_related, field_id/*, USHORT row_num, USHORT col_num*/);
	StrAnalyzeLine(addr);
	return TRUE;
}

/********************************************************
* Function:	FieldSetMaxNumChars
* Purpose:	Set the maximum numbers of char in the field object
* Scope:	Application
* Input:    field_id			DBID of the spceified field object
* Input:	max_num_of_chars	Maximum number of char in the field
*								object
* Ouput:	None
* Return:	Error code
*			UI_ERR_RES_NOT_FOUND;
* Comment:	None
*********************************************************/
Err FieldSetMaxNumChars(ObjectID field_id, WORD max_num_of_chars)
{
	Field *addr;
	BYTE object_type;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	addr->field_max_chars = max_num_of_chars;
	return TRUE;
}
/********************************************************
* Function:	FieldSetHighlightSelection
* Purpose:	Set the current selection in a field and highlight
*			the selection if the field is visible
* Scope:	Application
* Input:    field_id		DBID of the spceified field object
* 			start_char		Starting character position of the
*							character range to highlight
*			stop_char		Ending character position of the
*							character range to highlight
* Ouput:	None
* Return:	Error code
*			UI_ERR_RES_NOT_FOUND;
* Comment:	If the start_char equal stop_char, then the
*			field_highlight is reset
*********************************************************/
Err FieldSetHighlightSelection(ObjectID field_id, WORD start_char, WORD stop_char)
{
	Field *addr;
	BYTE object_type;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	if (start_char == stop_char)
		addr->field_attr.field_highlight = FALSE;
	else
	{
		addr->field_attr.field_highlight = TRUE;
		addr->field_highlight_start_char = start_char;
		addr->field_highlight_length = (stop_char-start_char)+1;
	}
	return TRUE;
}
/********************************************************
* Function:	FieldSendChangeNotification
* Purpose:	Send a EVT_FIELD_CHANGED_EVENT via the event queue
* Scope:	Application
* Input:    field_id			DBID of the spceified field object
* Ouput:	None
* Return:	None
* Comment:	None
*********************************************************/
BOOLEAN FieldSendChangeNotification(ObjectID field_id)
{
	Field *addr;
	BYTE object_type;
	
    if (UISearchForAddress(field_id,&object_type, (void**)&addr) != TRUE) return ERR_UI_RES_NOT_FOUND;
	EvtAppendEvt(EVT_FIELD_CHANGED, field_id, 0, 0, (void*)addr);
	return TRUE;
}
/********************************************************
* Function:	FieldGetNumBlankLines
* Purpose:	Get number of blank lines in the field
* Scope:	Application
* Input:	field_id		DBID of the spceified field object
* Output:	None
* Return:	Error code
*           UI_ERR_RES_NOT_FOUND;
* Comment:	None
**********************************************************/
Err FieldGetNumBlankLines (ObjectID field_id, UWORD *num_blank_line)
{
	Field *addr;
	BYTE object_type;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	*num_blank_line = addr->field_total_num_lines - addr->field_num_lines_displayed;
	return TRUE;
}
/********************************************************
* Function:	FieldDrawField
* Purpose:  Get the
* Scope:	Application
* Input:	field_id	DBID of the spceified field object
* Output:	None
* Return:	Error code
*           UI_ERR_RES_NOT_FOUND;
* Comment:	None
**********************************************************/
Err FieldDrawField (ObjectID field_id)
{
	Field *addr;
	BYTE object_type;
	ObjectBounds bounds;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	if (addr->field_attr.field_visible == FALSE) return FALSE;
	
#ifdef DEBUG
    printf("\n Field Draw Field");
#endif
	
#ifdef DEBUG
    if (field_id == 80 && strlen(addr->field_string) < 50)
    {
        printf("\n field_string = %s", addr->field_string);
        printf("\n screen_bounds.width = %ld", addr->screen_bounds.width);
    }
#endif
	
	if (addr->identification.table_related == 0xFFFF)
		bounds = addr->bounds;
	else
		bounds = addr->screen_bounds;
	
    if (addr->field_style == FIELD_STYLE_1)
        LcdDrawBox(&bounds,color_level[COLOR_BLACK_COLOR],color_level[COLOR_WHITE_COLOR],FILL_TRANSPARENT);
	
    if (LcdCheckInsertPt(bounds))
        LcdEnableInsertPt(FALSE, 0 , 0, FALSE);  
	
#ifdef DEBUG_KEY
	printf("\n Before LcdDrawVariableString %ld %ld", addr->field_attr.field_highlight, addr->field_attr.field_insert_pt_visible);
	printf("\n pt_x = %ld pt_y = %ld", addr->field_insert_pt_x, addr->field_insert_pt_y);
#endif	
	
	LcdDrawVariableString(addr);
	
#ifdef DEBUG_KEY
	printf("\n After LcdDrawVariableString %ld %ld", addr->field_attr.field_highlight, addr->field_attr.field_insert_pt_visible);
#endif	
	
	
	addr->field_attr.field_drawn = TRUE;
	
	if (addr->field_attr.field_insert_pt_visible == TRUE)
	{
		FieldInsertPtMove(field_id);
		LcdEnableInsertPt(TRUE,addr->field_insert_pt_x,addr->field_insert_pt_y, addr->field_font_id);
	}
	
	if (addr->field_total_num_lines > addr->field_num_lines_displayed)
		addr->field_attr.field_scrollbar = TRUE;
	else
		addr->field_attr.field_scrollbar = FALSE;
	
	return TRUE;
}

/********************************************************
* Function: FieldDrawField2
* Purpose:  Get the
* Scope:	Application
* Input:	field_id	DBID of the spceified field object
* Output:	None
* Return:	Error code
*           UI_ERR_RES_NOT_FOUND;
* Comment:  Without
**********************************************************/
Err FieldDrawField2 (ObjectID field_id)
{
	Field *addr;
	BYTE object_type;
	ObjectBounds bounds;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	if (addr->field_attr.field_visible == FALSE) return FALSE;
	
	if (addr->identification.table_related == 0xFFFF)
		bounds = addr->bounds;
	else
		bounds = addr->screen_bounds;
	
    if (addr->field_style == FIELD_STYLE_1)
        LcdDrawBox(&bounds,color_level[COLOR_BLACK_COLOR],color_level[COLOR_WHITE_COLOR],DRAW_NOT_FILL);
	
    if (LcdCheckInsertPt(bounds))
        LcdEnableInsertPt(FALSE, 0 , 0, FALSE);  
	
	LcdDrawVariableString(addr);
	addr->field_attr.field_drawn = TRUE;
	
	if (addr->field_attr.field_insert_pt_visible == TRUE)
	{
		FieldInsertPtMove(field_id);
		LcdEnableInsertPt(TRUE,addr->field_insert_pt_x,addr->field_insert_pt_y, addr->field_font_id);
	}
	return TRUE;
}
/********************************************************
* Function:	FieldCopy
* Purpose:  Copy the current selection to the text clipboard
* Scope:	Application
* Input:	field_id		DBID of the spceified field object
* Output:	None
* Return:	Error code
*           UI_ERR_RES_NOT_FOUND;
* Comment:	None
**********************************************************/
Err FieldCopy (ObjectID field_id)
{
	Field *addr;
	BYTE object_type, *text_pointer;
	WORD copy_start_char, copy_length;
	
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	if (addr->field_attr.field_highlight == TRUE)
	{
		copy_start_char = addr->field_highlight_start_char;
		copy_length = addr->field_highlight_length;
		
		if (addr->field_highlight_length < 0)
		{
			copy_start_char += addr->field_highlight_length;
			copy_length = abs(copy_length);
		}
        text_pointer = (BYTE*)qmalloc((copy_length+1)*sizeof(BYTE));
		StrExtract(addr->field_string,copy_start_char,copy_length,text_pointer);
		ClipboardPutItem(CLIP_TEXT_DATA,(void*)text_pointer,copy_length);
        qfree(text_pointer);
	}
	return TRUE;
}
/********************************************************
* Function:	FieldCut
* Purpose:  Copy the current selection to the text clipboard,
*			delete the selection from the field, and redraw
*			the field
* Scope:	Application
* Input:	field_id		DBID of the spceified field object
* Output:	None
* Return:	Error code
*           UI_ERR_RES_NOT_FOUND;
* Comment:	None
**********************************************************/
Err FieldCut (ObjectID field_id)
{
	Field *addr;
	BYTE object_type;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	if (addr->field_attr.field_highlight == TRUE)
	{
		FieldCutSelectedText (addr);
		undo_action = UNDO_CUT;
	}
	return TRUE;
}
/********************************************************
* Function:	FieldInsert
* Purpose:  Insert text from the clipboard to the field
* Scope:	Application
* Input:	field_id		DBID of the spceified field object
*			paste_size		Length of the text to be inserted
* Output:	None
* Return:	Error code
*           UI_ERR_RES_NOT_FOUND;
* Comment:	None
**********************************************************/
Err FieldInsert (ObjectID field_id, WORD *paste_size)
{
	Field *addr;
	BYTE object_type, data_type, *paste_text;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	paste_text = (BYTE *) ClipboardGetItem(&data_type,paste_size);
	if (paste_text == NULL) return TRUE;
	FieldInsertFunction(addr,paste_text,*paste_size);
    qfree(paste_text);
	return TRUE;
}
/********************************************************
* Function:	FieldInsertText
* Purpose:  Insert text to the specified field object
* Scope:	Application
* Input:	field_id		DBID of the spceified field object
*			insert_string	Pointer to the insert string
*			field_len		Length of the field
* Output:	None
* Return:	Error code      UI_ERR_RES_NOT_FOUND
* Comment:	None
**********************************************************/
Err FieldInsertText (ObjectID field_id, BYTE *insert_string, WORD field_len)
{
	Field *addr;
	BYTE object_type;
	
	
    if (UISearchForAddress(field_id, &object_type, (void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	if (addr->field_attr.field_insert_pt_visible == TRUE &&
		addr->field_attr.field_highlight == FALSE)
		FieldInsertFunction (addr,insert_string,field_len);
	
	if (addr->field_attr.field_insert_pt_visible == TRUE &&
		addr->field_attr.field_highlight == TRUE)
	{
		FieldCutSelectedText (addr);
		FieldInsertFunction (addr,insert_string,field_len);
	}
	return TRUE;
}

/********************************************************
* Function:	FieldStoreBackspaceChar
* Purpose:  This function is called in order to store backspace character
* Scope:	Internal
* Input:	field_id		DBID of the spceified field object
character		The character to be stored
* Output:	None
* Return:	Error code
* Comment:	None
**********************************************************/
Err FieldStoreBackspaceChar(ObjectID field_id, UBYTE character)
{
	BYTE object_type;
	Field *field_ptr;
	WORD count;
	
	if (UISearchForAddress(field_id, &object_type, (void**)&field_ptr) != TRUE) return ERR_UI_RES_NOT_FOUND;
	if (object_type != FIELD) return ERR_UI_OBJECT_NOT_MATCH;
	undo_action = UNDO_BACKSPACE;
	if (field_id != backspace_undo.current_object_id)
	{
		backspace_undo.current_object_id = field_id;
		backspace_undo.index = -1;
	}
	else if (field_id == backspace_undo.current_object_id && backspace_undo.index == 255)
	{
		count = 0;
		while (count < 255)
		{	
			backspace_undo.key[count] = backspace_undo.key[count + 1];
			count ++;
		}
	}
	if (backspace_undo.index != 255)
		backspace_undo.index ++;
	backspace_undo.key[backspace_undo.index] = character;
	return TRUE;
}

/********************************************************
* Function:	FieldRestoreBackspaceChar
* Purpose:  This function is called in order to restore backspace character			
* Scope:	Internal
* Input:	field_id		DBID of the spceified field object
* Output:	character		The character for restoration
* Return:	TRUE			if restored successfully
FALSE			can't restore
* Comment:	None
**********************************************************/
Err FieldRestoreBackspaceChar(ObjectID field_id, UBYTE *character)
{
	BYTE object_type;
	Field *field_ptr;
	
	
	if (UISearchForAddress(field_id, &object_type, (void**)&field_ptr) != TRUE) return ERR_UI_RES_NOT_FOUND;
	if (object_type != FIELD) return ERR_UI_OBJECT_NOT_MATCH;
	if (field_id != backspace_undo.current_object_id)
	{
		*character = 0;
		return FALSE;
	}
	if (backspace_undo.index != -1)
		*character = backspace_undo.key[backspace_undo.index];
	backspace_undo.index --;
	if (backspace_undo.index == -1) undo_action = UNDO_EMPTY;
	return TRUE;
}

/********************************************************
* Function:	FieldInsertFunction
* Purpose:  Insert text from the clipboard to the field
* Scope:	Application
* Input:	field_id		DBID of the spceified field object
*			addr			Pointer to the structure of the field object
*			paste_size		Length of the text
* Output:	None
* Return:	None
* Comment:	None
**********************************************************/
void FieldInsertFunction (Field *addr, BYTE *paste_text, WORD paste_size)
{
	BYTE *text_pointer;
	WORD insert_pos, total_length, org_total;
	WORD i, count=0, add_length, buffer_size;
	
	org_total = strlen(addr->field_string) + 1;
	total_length = org_total + paste_size;
	buffer_size = ((org_total-1)/STEP_SIZE + 1) * STEP_SIZE;
	insert_pos = addr->field_insert_pt_char_pos;
	
	if (total_length >= buffer_size)
	{
		while(total_length >= buffer_size)
			buffer_size += STEP_SIZE;
		
        text_pointer = (BYTE *)qmalloc(buffer_size*sizeof(BYTE));
		/* If insert pt is behind the field text, then copy the '\0' only */
		if (insert_pos > org_total-1)
			add_length = 1;
		else
			add_length = (org_total-insert_pos);
		
		i = insert_pos;
		while (i)
		{
			i--;
			text_pointer[i] = addr->field_string[i];
			count++;
		}
		/* Paste the text from clipboard to the field */
		i = paste_size;
		while (i)
		{
			i--;
			text_pointer[count] = *paste_text++;
			count++;
		}
		
		i = add_length;
		while (i)
		{
			i--;
			text_pointer[count] = addr->field_string[insert_pos++];
			count++;
		}
		
        qfree (addr->field_string);
		addr->field_string = text_pointer;
	}
	else
	{
		i = org_total;
		while (i >= insert_pos)
		{
			addr->field_string[total_length--] = addr->field_string[org_total--];
			i --;
		}
		
		/* Paste the text from clipboard to the field */
		i = paste_size;
		while (i)
		{
			i--;
			addr->field_string[insert_pos++] = *paste_text++;
		}
	}
	
	addr->field_current_num_chars = strlen(addr->field_string);
	undo_action = UNDO_PASTE;
}
/********************************************************
* Function:	FieldCutSelectedText
* Purpose:  Delete the specified range of characters from
*			the field and redraw the field
* Scope:	Application
* Input:	field_id		DBID of the spceified field object
* Output:	None
* Return:	None
* Comment:	None
**********************************************************/
void FieldCutSelectedText (Field *addr)
{
	BYTE *text_pointer;
	WORD total_length, add_length, text_cont_text, i, count;
	WORD cut_start_char, cut_length;
	
	cut_start_char = addr->field_highlight_start_char;
	cut_length = addr->field_highlight_length;
	
	if (!addr->field_attr.field_drawn)
		StrAnalyzeLine(addr);
	if (addr->field_highlight_length < 0)
	{
		cut_start_char += addr->field_highlight_length;
		cut_length = abs(cut_length);
	}
	
    text_pointer = (BYTE*)qmalloc((cut_length+1)*sizeof(BYTE));
	total_length = strlen(addr->field_string)+1;
	text_cont_text = cut_start_char + cut_length;
	add_length = total_length - text_cont_text;
	
	/* Extract the highlight region to text_pointer*/
	StrExtract(addr->field_string,cut_start_char,cut_length,text_pointer);
	ClipboardPutItem(CLIP_TEXT_DATA,(void*)text_pointer,cut_length);
	count = cut_start_char;
	
	for (i=0; i< add_length; i++)
	{
		addr->field_string[count] = addr->field_string[text_cont_text++];
		count++;
	}	
	
	addr->field_current_num_chars = strlen(addr->field_string);
	addr->field_attr.field_highlight == FALSE;
	undo_action = UNDO_CUT;
    qfree(text_pointer);
}
/********************************************************
* Function:	FieldDelete
* Purpose:  Delete the specified range of characters from
*			the field and redraw the field
* Scope:	Application
* Input:	field_id		DBID of the spceified field object
*			start_char		start character position
*			cut_length 		Length to cut
* Output:	None
* Return:	Error code
*           UI_ERR_RES_NOT_FOUND;
* Comment:	None
**********************************************************/
Err FieldDelete (ObjectID field_id, WORD start_char, WORD cut_length)
{
	Field *addr;
	BYTE object_type;
	WORD total_length, text_cont_text, add_length, i;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	if (cut_length < 0)
	{
		start_char += cut_length;
		cut_length = -cut_length;
	}
	
	total_length = strlen(addr->field_string)+1;
	text_cont_text = start_char+cut_length;
	
	if (text_cont_text > total_length)
		add_length = 0;
	else
		add_length = total_length-text_cont_text;
	
	for (i=0; i< add_length; i++)
		addr->field_string[start_char++] = addr->field_string[text_cont_text++];
	
	addr->field_current_num_chars = strlen(addr->field_string);
	return TRUE;
}

/********************************************************
* Function:	FieldUndo
* Purpose:  Undo the last change made to the field object.
* Scope:	Application
* Input:	field_id		DBID of the spceified field object
* Output:	None
* Return:	Error code
*           UI_ERR_RES_NOT_FOUND;
* Comment:	None
**********************************************************/
Err FieldUndo (ObjectID field_id)
{
	Field *addr;
	BYTE object_type, data_type, *paste_text;
	WORD undo_size;
    ObjectBounds bounds;
    SHORT xcoord,ycoord;
    WORD row_num;
    WORD line_num;
	WORD max_num_lines_displayed;
	UBYTE character;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	switch(undo_action)
	{
	case UNDO_TYPING:
		if (typing_undo.focus_object_id != field_id)
			return FALSE;
		addr->field_insert_pt_char_pos = typing_undo.start_char;
		FieldDelete (field_id, typing_undo.start_char, typing_undo.length);
		undo_action = UNDO_EMPTY;
		typing_undo.focus_object_id = 0xFFFF;
		typing_undo.start_char = 0;
		typing_undo.length = -1;
		StrAnalyzeLine(addr);
		FieldCharPosToLineNum (addr, addr->field_insert_pt_char_pos, &line_num);               	
		line_num -= addr->field_top_line_num;
		if (addr->identification.table_related == 0xFFFF)
			bounds = addr->bounds;
		else bounds = addr->screen_bounds;
		if (line_num <0) addr->field_top_line_num += line_num;   	
		if (line_num > ((bounds.height - 2 * (SHORT)(addr->field_style))/(FONT_HEIGHT[addr->field_font_id] + SPACE_LINE)))
			addr->field_top_line_num += line_num;
		StrAnalyzeLine(addr);	
		max_num_lines_displayed = ((bounds.height - 2 * (SHORT)(addr->field_style))/(FONT_HEIGHT[addr->field_font_id] + SPACE_LINE));
		if (addr->field_num_lines_displayed < max_num_lines_displayed) 	
		{
			StrAnalyzeLine(addr);
			FieldCharPosToLineNum (addr, addr->field_insert_pt_char_pos, &line_num);
			line_num -= addr->field_top_line_num;
			row_num = min((max_num_lines_displayed - line_num - 1), (max_num_lines_displayed - addr->field_num_lines_displayed));
			addr->field_top_line_num -= row_num;
			if (addr->field_top_line_num < 0)
				addr->field_top_line_num = 0;
		}
		StrAnalyzeLine(addr);				   
		StrCharPosToXY(addr,addr->field_insert_pt_char_pos,
			&(addr->field_insert_pt_x), &(addr->field_insert_pt_y));			   
		EvtAppendEvt(EVT_FIELD_CHANGED, field_id, 0, 0, (void*)addr);
		EvtAppendEvt(EVT_FIELD_MODIFIED, field_id, 0, 0, (void*)addr);
		addr->field_attr.field_highlight = FALSE;
		addr->field_highlight_length = 0;
		addr->field_attr.field_insert_pt_visible = TRUE;
		if (addr->field_attr.field_drawn == TRUE)
			FieldDrawField(field_id);
		return TRUE;	
	case UNDO_BACKSPACE:
		if (FieldRestoreBackspaceChar(field_id, &character) == FALSE) return TRUE;
		addr->field_attr.field_insert_pt_visible = TRUE;
		FieldAddKeyInChar(field_id, character);
		if (backspace_undo.index != -1)
			undo_action = UNDO_BACKSPACE;
		EvtAppendEvt(EVT_FIELD_CHANGED, field_id, 0, 0, (void*)addr);
		EvtAppendEvt(EVT_FIELD_MODIFIED, field_id, 0, 0, (void*)addr);
		return TRUE;
	case UNDO_BACKSPACE_HIGHLIGHT:
		if (undo_buffer.clipboard_type == CLIP_EMPTY)
			return FALSE;
		LcdEnableInsertPt(FALSE,0,0, 0);
		undo_size = undo_buffer.clipboard_size;
		FieldInsertFunction(addr,(BYTE*)undo_buffer.clipboard_data, undo_size);
		if (undo_buffer.clipboard_type == CLIP_TEXT_DATA)
		{
			undo_buffer.clipboard_type = CLIP_EMPTY;
			undo_buffer.clipboard_size = 0;
			qfree(undo_buffer.clipboard_data);
		}
		addr->field_insert_pt_char_pos += undo_size;
		StrAnalyzeLine(addr);
		StrCharPosToXY(addr, addr->field_insert_pt_char_pos,
			&(addr->field_insert_pt_x),
			&(addr->field_insert_pt_y));
		FieldCharPosToLineNum (addr, addr->field_insert_pt_char_pos, &line_num);               
		line_num = line_num - (addr->field_top_line_num + addr->field_num_lines_displayed - 1);
		if (line_num > 0)
			addr->field_top_line_num = line_num + addr->field_top_line_num;			   
		StrAnalyzeLine(addr);
		StrCharPosToXY(addr, addr->field_insert_pt_char_pos,
			&(addr->field_insert_pt_x),
			&(addr->field_insert_pt_y));
		EvtAppendEvt(EVT_FIELD_CHANGED, field_id, 0, 0, (void*)addr);
		EvtAppendEvt(EVT_FIELD_MODIFIED, field_id, 0, 0, (void*)addr);
		addr->field_highlight_start_char = addr->field_highlight_end_char;
		addr->field_highlight_length = 0;
		addr->field_attr.field_insert_pt_visible = TRUE;
		addr->field_attr.field_highlight = FALSE;
		if (addr->field_attr.field_drawn == TRUE)
			FieldDrawField(field_id);
		undo_action = UNDO_EMPTY;
		break;	
	case UNDO_CUT:		
		LcdEnableInsertPt(FALSE,0,0, 0);	
		if (undo_buffer.clipboard_type == CLIP_TEXT_DATA)
		{
			undo_buffer.clipboard_type = CLIP_EMPTY;
			undo_buffer.clipboard_size = 0;
			qfree(undo_buffer.clipboard_data);
		}
		paste_text = (BYTE *) ClipboardGetItem(&data_type,&undo_size);		   
		FieldInsertFunction(addr,paste_text,undo_size);
		qfree(paste_text);
		addr->field_insert_pt_char_pos += undo_size;
		StrAnalyzeLine(addr);
		StrCharPosToXY(addr, addr->field_insert_pt_char_pos,
			&(addr->field_insert_pt_x),
			&(addr->field_insert_pt_y));
		FieldCharPosToLineNum (addr, addr->field_insert_pt_char_pos, &line_num);               
		line_num = line_num - (addr->field_top_line_num + addr->field_num_lines_displayed - 1);
		if (line_num > 0)
			addr->field_top_line_num = line_num + addr->field_top_line_num;			   
		StrAnalyzeLine(addr);
		StrCharPosToXY(addr, addr->field_insert_pt_char_pos,
			&(addr->field_insert_pt_x),
			&(addr->field_insert_pt_y));
		EvtAppendEvt(EVT_FIELD_CHANGED, field_id, 0, 0, (void*)addr);
		EvtAppendEvt(EVT_FIELD_MODIFIED, field_id, 0, 0, (void*)addr);
		addr->field_highlight_start_char = addr->field_highlight_end_char;
		addr->field_highlight_length = 0;
		addr->field_attr.field_insert_pt_visible = TRUE;
		addr->field_attr.field_highlight = FALSE;
		if (addr->field_attr.field_drawn == TRUE)
			FieldDrawField(field_id);
		undo_action = UNDO_EMPTY;
		break;	
	case UNDO_PASTE:	
		undo_action = UNDO_EMPTY;	
		LcdEnableInsertPt(FALSE,0,0,0);
		paste_text = (BYTE*) ClipboardGetItem(&data_type,&undo_size);
		if (data_type != CLIP_EMPTY)
			qfree(paste_text);
		StrAnalyzeLine(addr);
		StrGetInsertPtPos(addr,addr->field_insert_pt_x,addr->field_insert_pt_y,
			&addr->field_insert_pt_char_pos, &xcoord, &ycoord);
		addr->field_insert_pt_char_pos -= undo_size;
		FieldDelete (field_id,addr->field_insert_pt_char_pos,undo_size);
		if (undo_buffer.clipboard_type == CLIP_TEXT_DATA)
		{
			undo_buffer.clipboard_type = CLIP_EMPTY;
			FieldInsertFunction (addr, (BYTE*)undo_buffer.clipboard_data, undo_buffer.clipboard_size);
			qfree(undo_buffer.clipboard_data);
			addr->field_insert_pt_char_pos += (undo_buffer.clipboard_size);			 
		}  
		StrAnalyzeLine(addr);
		FieldCharPosToLineNum (addr, addr->field_insert_pt_char_pos, &line_num);               	
		line_num -= addr->field_top_line_num;
		if (addr->identification.table_related == 0xFFFF)
			bounds = addr->bounds;
		else bounds = addr->screen_bounds;
		if (line_num <0) addr->field_top_line_num += line_num;   	
		if (line_num > ((bounds.height - 2 * (SHORT)(addr->field_style))/(FONT_HEIGHT[addr->field_font_id] + SPACE_LINE)))
			addr->field_top_line_num += line_num;
		StrAnalyzeLine(addr);	
		max_num_lines_displayed = ((bounds.height - 2 * (SHORT)(addr->field_style))/(FONT_HEIGHT[addr->field_font_id] + SPACE_LINE));
		if (addr->field_num_lines_displayed < max_num_lines_displayed) 	
		{
			StrAnalyzeLine(addr);
			FieldCharPosToLineNum (addr, addr->field_insert_pt_char_pos, &line_num);
			line_num -= addr->field_top_line_num;
			row_num = min((max_num_lines_displayed - line_num - 1), (max_num_lines_displayed - addr->field_num_lines_displayed));
			addr->field_top_line_num -= row_num;
			if (addr->field_top_line_num < 0) addr->field_top_line_num = 0;
		}
		StrAnalyzeLine(addr);				   
		StrCharPosToXY(addr,addr->field_insert_pt_char_pos,
			&(addr->field_insert_pt_x), &(addr->field_insert_pt_y));			   
		EvtAppendEvt(EVT_FIELD_CHANGED, field_id, 0, 0, (void*)addr);
		EvtAppendEvt(EVT_FIELD_MODIFIED, field_id, 0, 0, (void*)addr);
		addr->field_attr.field_highlight = FALSE;
		addr->field_highlight_length = 0;
		addr->field_attr.field_insert_pt_visible = TRUE;
		if (addr->field_attr.field_drawn == TRUE)
			FieldDrawField(field_id);
		undo_action = UNDO_EMPTY;                   
		return TRUE;
	default: break;
	}
	return TRUE;
}

/********************************************************
* Function:	FieldGetFirstVisibleChar
* Purpose:	Get the first visible character
* Scope:	Application
* Input:	field_id		DBID of the spceified field object
* Output:	char_pos		Character position
* Return:	Error code
*           UI_ERR_RES_NOT_FOUND;
* Comment:	None
**********************************************************/
Err FieldGetFirstVisibleChar (ObjectID field_id, WORD *char_pos)
{
	Field *addr;
	BYTE object_type;
	ObjectBounds bounds;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	if (addr->identification.table_related == 0xFFFF)
		bounds = addr->bounds;
	else
		bounds = addr->screen_bounds;
	
	StrAnalyzeLine(addr);
	StrXYToCharPos(addr,bounds.xcoord,bounds.ycoord,char_pos);
	return TRUE;
}
/********************************************************
* Function:	FieldGetLastVisibleChar
* Purpose:	Get the last visible character
* Scope:	Application
* Input:	field_id		DBID of the spceified field object
* Output:	char_pos		Character position
* Return:	Error code
*           UI_ERR_RES_NOT_FOUND;
* Comment:	None
**********************************************************/
Err FieldGetLastVisibleChar (ObjectID field_id, WORD *char_pos)
{
	Field *addr;
	BYTE object_type;
	ObjectBounds bounds;
	SHORT xcoord, ycoord;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	if (addr->identification.table_related == 0xFFFF)
		bounds = addr->bounds;
	else
		bounds = addr->screen_bounds;
	StrAnalyzeLine(addr);
	if ((addr->field_top_line_num + addr->field_num_lines_displayed) == addr->field_total_num_lines)
		StrGetInsertPtPos(addr,(bounds.xcoord+bounds.width-1),(bounds.ycoord+bounds.height-1),char_pos,
		&xcoord,&ycoord);
	else StrXYToCharPos(addr,(bounds.xcoord+bounds.width-1),(bounds.ycoord+bounds.height-1),char_pos);
	return TRUE;
}
/********************************************************
* Function:	FieldGetDisplayRowNum
* Purpose:	Get the corresponding row number of the specified
*			character
* Scope:	Application
* Input:	field_id		DBID of the spceified field object
*			input_x			Input x-coordinate of the character
*			input_y			Input y-coordinate of the character
* Output:	row_num			Row number of the specified character
* Return:	Error code
*           UI_ERR_RES_NOT_FOUND;
* Comment:	None
**********************************************************/
Err FieldGetDisplayRowNum (ObjectID field_id, SHORT input_y, WORD *row_num)
{
	Field *addr;
	BYTE object_type;
	ObjectBounds bounds;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	if (addr->identification.table_related == 0xFFFF)
		bounds = addr->bounds;
	else
		bounds = addr->screen_bounds;
	
	*row_num = ((input_y - (bounds.ycoord - (SHORT)(addr->field_style))+1))/(FONT_HEIGHT[addr->field_font_id]+SPACE_LINE);
	return TRUE;
}
/********************************************************
* Function:	FieldInsertPtMove
* Purpose:	Get the last visible character
* Scope:	Application
* Input:	field_id		DBID of the spceified field object
* Output:	None
* Return:	Error code
*           UI_ERR_RES_NOT_FOUND;
* Comment:	None
**********************************************************/
Err FieldInsertPtMove (ObjectID field_id)
{
	Field *addr;
	BYTE object_type;
	WORD char_pos;
	SHORT new_xcoord, new_ycoord;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	StrAnalyzeLine(addr);
	switch (addr->field_insert_pt_movement)
	{
	case MOVE_UP: 	addr->field_insert_pt_y -= FONT_HEIGHT[addr->field_font_id]+SPACE_LINE;
		StrGetInsertPtPos(addr,addr->field_insert_pt_x,addr->field_insert_pt_y,
										  &char_pos,&new_xcoord,&new_ycoord);
		break;
	case MOVE_DOWN: addr->field_insert_pt_y += FONT_HEIGHT[addr->field_font_id]+SPACE_LINE;
		StrGetInsertPtPos(addr,addr->field_insert_pt_x,addr->field_insert_pt_y,
										  &char_pos,&new_xcoord,&new_ycoord);
		break;
	case MOVE_LEFT:	addr->field_insert_pt_char_pos -= 1;
		char_pos = addr->field_insert_pt_char_pos;
		StrCharPosToXY(addr,addr->field_insert_pt_char_pos,&new_xcoord,&new_ycoord);
		break;
	case MOVE_RIGHT: addr->field_insert_pt_char_pos += 1;
		char_pos = addr->field_insert_pt_char_pos;
		StrCharPosToXY(addr,addr->field_insert_pt_char_pos,&new_xcoord,&new_ycoord);
		break;
	case NO_MOVEMENT: return TRUE;
	default: break;
	}
	addr->field_insert_pt_x = new_xcoord;
	addr->field_insert_pt_y = new_ycoord;
	addr->field_insert_pt_char_pos = char_pos;
	addr->field_insert_pt_movement = NO_MOVEMENT;
	return TRUE;
}
/********************************************************
* Function:	FieldCharPosToLineNum
* Purpose:	Get the last visible character
* Scope:	Application
* Input:	addr		Pointer to field object
char_pos	Char position
* Output:	line_num	Pointer to the value of line num of the character
* Return:	Error code
*           UI_ERR_NOT_VALID_CHAR_POS;
* Comment:	None
**********************************************************/
Err FieldCharPosToLineNum (Field *addr, WORD char_pos, WORD *line_num)
{
	
	WORD i;
	
#ifdef DEBUG_TAB
    printf("\n ========== In char Pos To Line Num ============");
    printf("\n input char_pos = %ld", char_pos);
#endif
	
	for (i = 0; i<addr->field_total_num_lines;i++)
	{
#ifdef DEBUG_TAB
        printf("\n Line Num %ld start = %ld length = %ld", i, addr->field_lineinfo[i].start, addr->field_lineinfo[i].length);
#endif
		
		if (i != (addr->field_total_num_lines - 1))
		{
			if (char_pos >= addr->field_lineinfo[i].start && char_pos < addr->field_lineinfo[i+1].start)
			{	
				*line_num = i;
				return TRUE;
			}
		}
		else
		{
			//Bug Fixed 10-Feb-2001
			//If char_pos is invalid, dont return TRUE
			//---------------------------------------------------------------- Modifying Codes 
			if (char_pos >= addr->field_lineinfo[i].start
				&& char_pos <= (addr->field_lineinfo[i].start + addr->field_lineinfo[i].length))
			{
				*line_num = i;
				return TRUE;
			}
			//---------------------------------------------------------------- Modifying Codes
		}
	}
#ifdef DEBUG_TAB
    printf("\n =====Error Exit char Pos To Line Num Error ===========");
#endif
	
	return ERR_UI_NOT_VALID_CHAR_POS;
}

/********************************************************
* Function:	FieldAddKeyInChar
* Purpose:	Add the key in character to the content of a field object
* Scope:	Application
* Input:	field_id	DBID of a field object
char		ascii of the char
* Output:	None
* Return:	Error code
*           UI_ERR_NOT_VALID_CHAR_POS
*			ERR_UI_FIELD_OVER_MAX_NUM_CHARS
* Comment:	the position of the insertion point is adjusted too
**********************************************************/
Err FieldAddKeyInChar(ObjectID field_id, BYTE key)
{
	Field   *addr;
	BYTE    object_type;
	WORD    line_num, max_num_lines;
	WORD    char_pos;
	WORD    first_char_pos, last_char_pos;
	BYTE	temp_undo_action;
	
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
    if (!addr->field_attr.field_drawn) 
		return FALSE;
	if ((UBYTE)key < 32 && key != '\r' && key != '\n' && key != 9)
		return TRUE; 	
	
	temp_undo_action = undo_action;
	
    LcdEnableInsertPt(FALSE, 0, 0, 0);
	
    if (addr->field_attr.field_highlight == TRUE)
    {
		FieldDelete(field_id, addr->field_highlight_start_char, addr->field_highlight_length);
		StrAnalyzeLine(addr);
		
		if (addr->field_highlight_length <0)
			addr->field_insert_pt_char_pos = addr->field_highlight_end_char;		 
		else addr->field_insert_pt_char_pos = addr->field_highlight_start_char;
		FieldCharPosToLineNum (addr, addr->field_insert_pt_char_pos, &line_num);
		
		if (addr->field_top_line_num > line_num)	
			addr->field_top_line_num = line_num;
		
		StrAnalyzeLine(addr);
		StrCharPosToXY(addr,addr->field_insert_pt_char_pos, &(addr->field_insert_pt_x), &(addr->field_insert_pt_y));
		addr->field_highlight_start_char = addr->field_highlight_end_char;
		addr->field_attr.field_highlight = FALSE;
		addr->field_highlight_length = 0;
		addr->field_attr.field_insert_pt_visible = TRUE;
	}
	
	
	if (insert == FALSE)
    {
		if (addr->field_insert_pt_char_pos < addr->field_current_num_chars)		   
			FieldDelete(field_id, addr->field_insert_pt_char_pos, 1);               
	}
	
	
	if (addr->field_current_num_chars < addr->field_max_chars)
	{
		//   	FieldInsertText(field_id,&key, 1);
		//	  	addr->field_insert_pt_char_pos++;
		if(InsertTextFunction != 0)
			InsertTextFunction(field_id, object_type, addr, key);
		else
		{
			FieldInsertText(field_id,&key,1);
			addr->field_insert_pt_char_pos++;
		}
		
		StrAnalyzeLine(addr);  	
		
		FieldGetLastVisibleChar (field_id, &last_char_pos);
        FieldGetFirstVisibleChar (field_id, &first_char_pos);	  	
        FieldGetMaxNumLinesDisplay(field_id, &max_num_lines);
        
		FieldCharPosToLineNum (addr, addr->field_insert_pt_char_pos, &line_num);
		
        if (addr->field_total_num_lines <= max_num_lines)
			addr->field_top_line_num = 0;
		else if (addr->field_num_lines_displayed < max_num_lines)
		{
            if (addr->field_top_line_num >= (addr->field_total_num_lines - max_num_lines))
                addr->field_top_line_num = (addr->field_total_num_lines - max_num_lines);         
            else if (line_num < addr->field_top_line_num)
                addr->field_top_line_num = line_num;
            else if (line_num >= (addr->field_top_line_num + addr->field_num_lines_displayed))
                addr->field_top_line_num += addr->field_num_lines_displayed;                        	  	    	  	    
        }  	
        else
        {
            if ((last_char_pos < addr->field_insert_pt_char_pos) && (line_num >= (addr->field_top_line_num + addr->field_num_lines_displayed)))
                addr->field_top_line_num++;
        }
		
		StrAnalyzeLine(addr);
		StrCharPosToXY(addr, addr->field_insert_pt_char_pos,
			&(addr->field_insert_pt_x), &(addr->field_insert_pt_y));		   		          		       
		
		EvtAppendEvt(EVT_FIELD_CHANGED, field_id, 0, 0, (void*)addr);
		EvtAppendEvt(EVT_FIELD_MODIFIED, field_id, 0, 0, (void*)addr);
	}
	else
	{
		FieldDrawField(field_id);
		return ERR_UI_FIELD_OVER_MAX_NUM_CHARS;
	}
	
    if (addr->field_attr.field_drawn == TRUE)
    {
        FieldDrawField(field_id);
	}        
	
	if (undo_buffer.clipboard_type != CLIP_EMPTY)
	{
		undo_buffer.clipboard_type = CLIP_EMPTY;
		if (undo_buffer.clipboard_data)
			qfree(undo_buffer.clipboard_data);
	}
	
	if (temp_undo_action != UNDO_TYPING)
	{
		typing_undo.focus_object_id = addr->identification.ui_object_id;
		typing_undo.start_char = addr->field_insert_pt_char_pos - 1;
		typing_undo.length = 1;
		backspace_undo.index = -1;
	}
	else if (temp_undo_action == UNDO_TYPING)
	{
		typing_undo.length ++;
	}			
	undo_action = UNDO_TYPING;
	addr->field_attr.field_dirty = TRUE;
	
	return TRUE;
}

/********************************************************
* Function:	FieldInitField
* Purpose:		1) to initialise the field object
2) to read the resource file
3) to create a corresponding field structure
in RAM
* Scope:		Application
* Input:		control_id	DBID of the line object
* Output:		None
* Return:      TRUE if no error
* Comment:     None
*********************************************************/
Err FieldInitField(ObjectID field_id)
{
	BYTE *buffer;
	UWORD byte_return;
	void *temp;
	Field *addr;
	Err Error;
	BYTE object_type;
	USHORT temp_length,temp_length1;
	
	
	object_type = FIELD;
	
	Error = UIAddressToLookupTable(field_id,object_type,&temp); /*put the pointer to the DBID											  lookup table */
	if (Error != TRUE) return Error;
	addr = (Field *)temp;
    Error = ResOpen(field_id);
    if (Error != TRUE) return Error;
	
	addr->identification.ui_object_id = field_id;
	/* Field 0 */
	addr->identification.ui_object_type = FIELD;
	/* Field 1 */
	ResGetField(field_id,1,&buffer,&byte_return);
	
	
	addr->identification.table_related = *(ObjectID*)buffer;
    qfree(buffer);
	/* Field 2 */
	ResReadField(field_id,2,0,2,&buffer,&byte_return);
	
	addr->bounds.xcoord = *(SHORT*)buffer;
    qfree(buffer);
	ResReadField(field_id,2,2,2,&buffer,&byte_return);
	
	addr->bounds.ycoord = *(SHORT*)buffer;
    qfree(buffer);
	ResReadField(field_id,2,4,2,&buffer,&byte_return);
	
	addr->bounds.width = *(SHORT*)buffer;
    qfree(buffer);
	ResReadField(field_id,2,6,2,&buffer,&byte_return);
	
	addr->bounds.height = *(SHORT*)buffer;
    qfree(buffer);
	/* Field 3 */
	ResGetField(field_id,3,&buffer,&byte_return);
	
	temp_length = strlen(buffer);
	temp_length1 = ((temp_length)/STEP_SIZE + 1) * STEP_SIZE;
    addr->field_string = (BYTE*)qmalloc(temp_length1*sizeof(BYTE));
	
	strcpy(addr->field_string,buffer);
	
    qfree(buffer);
	
	/* Field 4 */
	ResGetField(field_id,4,&buffer,&byte_return);
	
	addr->field_style = *buffer;
    qfree(buffer);
	/* Field 5 */
	ResGetField(field_id,5,&buffer,&byte_return);
	
	addr->field_back_line = *buffer;
    qfree(buffer);
	/* Field 6 */
	ResGetField(field_id,6,&buffer,&byte_return);
	
	addr->field_font_id = *buffer;
    qfree(buffer);
	/* Field 7 */
	ResGetField(field_id,7,&buffer,&byte_return);
	
	addr->field_font_color = UIColorConversion(*buffer);
    qfree(buffer);
	/* Field 8 */
	ResGetField(field_id,8,&buffer,&byte_return);
	
	addr->field_background_color = UIColorConversion(*buffer);
    qfree(buffer);
	/* Field 9 */
	ResGetField(field_id,9,&buffer,&byte_return);
	
	addr->field_text_alignment = *buffer;
    qfree(buffer);
	/* Field 10 */
	ResGetField(field_id,10,&buffer,&byte_return);
	
	addr->field_max_chars = *(WORD*)buffer;
    qfree(buffer);
	
	addr->field_current_num_chars = strlen(addr->field_string);
	addr->field_total_num_lines = 0;
	
	/* Field 11 */
	ResGetField(field_id,11,&buffer,&byte_return);
	addr->field_top_line_num = *(WORD*)buffer;
    qfree(buffer);
	
	addr->field_num_lines_displayed = 0;
	
	
	/* Field 12 */
	ResGetField(field_id,12,&buffer,&byte_return);
	
	addr->field_insert_pt_char_pos = *(WORD*)buffer;
    qfree(buffer);
	
	addr->field_lineinfo = NULL;
	
	
	
	StrAnalyzeLine(addr);
	StrCharPosToXY(addr,addr->field_insert_pt_char_pos,
		&(addr->field_insert_pt_x), &(addr->field_insert_pt_y));
	
	
	
	addr->field_insert_pt_movement = NO_MOVEMENT;
	
	/* Field 13 */
	ResGetField(field_id,13,&buffer,&byte_return);
	addr->field_highlight_start_char = *(WORD*)buffer;
    qfree(buffer);
	
	/* Field 14 */
	ResGetField(field_id,14,&buffer,&byte_return);
	addr->field_highlight_end_char = *(WORD*)buffer;
    qfree(buffer);
	
    addr->field_highlight_length = addr->field_highlight_end_char - addr->field_highlight_start_char;
	addr->field_repeat_count = 0;
	/* Field 15 */
	addr->field_attr.field_drawn = FALSE;
	ResReadField(field_id,15,0,2,&buffer,&byte_return);
	addr->field_attr.field_active = *(BOOLEAN*)buffer;
	
	
    qfree(buffer);
	ResReadField(field_id,15,2,2,&buffer,&byte_return);
	addr->field_attr.field_enable = *(BOOLEAN*)buffer;
    qfree(buffer);
	ResReadField(field_id,15,4,2,&buffer,&byte_return);
	addr->field_attr.field_dirty = *(BOOLEAN*)buffer;
    qfree(buffer);
	ResReadField(field_id,15,6,2,&buffer,&byte_return);
	addr->field_attr.field_highlight = *(BOOLEAN*)buffer;
    qfree(buffer);
	ResReadField(field_id,15,8,2,&buffer,&byte_return);
	addr->field_attr.field_insert_pt_visible = *(BOOLEAN*)buffer;
    qfree(buffer);
	ResReadField(field_id,15,10,2,&buffer,&byte_return);
	addr->field_attr.field_scrollbar = *(BOOLEAN*)buffer;
    qfree(buffer);
	ResReadField(field_id,15,12,2,&buffer,&byte_return);
	addr->field_attr.field_full_size = *(BOOLEAN*)buffer;
    qfree(buffer);
	ResReadField(field_id,15,14,2,&buffer,&byte_return);
	addr->field_attr.field_visible = *(BOOLEAN*)buffer;
	
    qfree(buffer);
	
	ResClose(field_id);
	return TRUE;
}

/********************************************************
* Function:    FieldPasteString
* Purpose:     This function is called to paste a string inro the
field object
* Scope:		Application
* Input:       field_id   field id
* Output:		None
* Return:      TRUE if no error
ERR_UI_RES_NOT_FOUND
* Comment:     Won't re-draw the object for u
*********************************************************/
Err FieldPasteString(ObjectID field_id, BYTE *paste_string)
{
	
    BYTE            object_type;
    Field           *field_ptr;
    WORD            paste_size = 0, cut_start_char = 0, cut_length = 0, temp_line_num = 0;
    BYTE            *text_pointer;
    ObjectBounds    bounds;
    WORD            line_num;
	
    if (UISearchForAddress(field_id, &object_type, (void**)&field_ptr) != TRUE)
        return ERR_UI_RES_NOT_FOUND;
	
    if (paste_string == NULL) return FALSE;
	
    paste_size = strlen(paste_string);
	
    if (field_ptr->field_attr.field_highlight == FALSE)
    {
        if ((paste_size + field_ptr->field_current_num_chars) > field_ptr->field_max_chars)
            return FALSE;
    } 
    else
    {
        if ((paste_size + field_ptr->field_current_num_chars - abs(field_ptr->field_highlight_length)) > field_ptr->field_max_chars)
            return FALSE;
    }
	
	
    LcdEnableInsertPt(FALSE,0,0,0);
	
    if (field_ptr->field_attr.field_highlight == FALSE)
    {
		FieldInsertString(field_id, paste_string);
		field_ptr->field_insert_pt_char_pos += strlen(paste_string);
    }
    else
    {
		cut_start_char = field_ptr->field_highlight_start_char;
		cut_length = field_ptr->field_highlight_length;
		if (field_ptr->field_highlight_length < 0)
		{
			cut_start_char += field_ptr->field_highlight_length;
			cut_length = abs(cut_length);
		}
		
		if (undo_buffer.clipboard_type == CLIP_TEXT_DATA)
		{
			undo_buffer.clipboard_type = CLIP_EMPTY;
			undo_buffer.clipboard_size = 0;
			qfree(undo_buffer.clipboard_data);
		}
		
		FieldDeleteString(field_id, field_ptr->field_highlight_start_char, field_ptr->field_highlight_length);
		field_ptr->field_insert_pt_char_pos = cut_start_char;
		
		FieldInsertString(field_id, paste_string);
		field_ptr->field_current_num_chars = strlen(field_ptr->field_string);
		field_ptr->field_insert_pt_char_pos += paste_size;
    }
    undo_action = UNDO_EMPTY;
	
    if (field_ptr->identification.table_related == 0xFFFF)
		bounds = field_ptr->bounds;
    else bounds = field_ptr->screen_bounds;
	
    StrAnalyzeLine(field_ptr);
	
    FieldCharPosToLineNum (field_ptr, field_ptr->field_insert_pt_char_pos, &line_num);
	
    temp_line_num = line_num;
    temp_line_num -= field_ptr->field_top_line_num;
	
    if (temp_line_num <0)
    {
        if (field_ptr->field_top_line_num >= (-temp_line_num))
            field_ptr->field_top_line_num += temp_line_num;
        else field_ptr->field_top_line_num = 0;    
    }
	
    if (temp_line_num >= 0 && field_ptr->field_num_lines_displayed < ((bounds.height - 2 * (SHORT)(field_ptr->field_style))/(FONT_HEIGHT[field_ptr->field_font_id] + SPACE_LINE)))
    {
        field_ptr->field_top_line_num -= ((bounds.height - 2 * (SHORT)(field_ptr->field_style))/(FONT_HEIGHT[field_ptr->field_font_id] + SPACE_LINE)) - field_ptr->field_num_lines_displayed;
        if (field_ptr->field_top_line_num < 0)
            field_ptr->field_top_line_num = 0;
    }
	
    if (temp_line_num > (field_ptr->field_num_lines_displayed - 1))
    {
        field_ptr->field_top_line_num += temp_line_num - (field_ptr->field_num_lines_displayed - 1); 
        if (field_ptr->field_top_line_num > field_ptr->field_total_num_lines - field_ptr->field_num_lines_displayed)
            field_ptr->field_top_line_num = field_ptr->field_total_num_lines - field_ptr->field_num_lines_displayed;
    }
	
    StrAnalyzeLine(field_ptr);
    StrCharPosToXY(field_ptr, field_ptr->field_insert_pt_char_pos,
		&(field_ptr->field_insert_pt_x),
		&(field_ptr->field_insert_pt_y));
	
    field_ptr->field_highlight_start_char = field_ptr->field_highlight_end_char;
    field_ptr->field_highlight_length = 0;
    field_ptr->field_attr.field_insert_pt_visible = TRUE;
    field_ptr->field_attr.field_highlight = FALSE;
    field_ptr->field_attr.field_dirty = TRUE;
    EvtAppendEvt(EVT_FIELD_CHANGED, field_id, 0, 0, (void*)field_ptr);
    EvtAppendEvt(EVT_FIELD_MODIFIED, field_id, 0, 0, (void*)field_ptr);
    return TRUE;
}

/********************************************************
* Function:    FieldInsertString
* Purpose:     This function is called to insert a string to
field object
* Scope:		Application
* Input:       field_id
paste_string
* Output:		None
* Return:      TRUE if no error
ERR_UI_RES_NOT_FOUND
* Comment:     Won't re-draw the object for u
*********************************************************/
Err FieldInsertString(ObjectID field_id, BYTE *paste_string)
{
    BYTE    object_type;
    Field   *addr;
	
    if (UISearchForAddress(field_id, &object_type, (void**)&addr) != TRUE)
        return ERR_UI_RES_NOT_FOUND;
	
	FieldInsertFunction(addr, paste_string, strlen(paste_string));
	return TRUE;
}

/********************************************************
* Function:    FieldDeleteString
* Purpose:     This function is called to delete a string
in the field object
* Scope:		Application
* Input:       field_id
* Output:		None
* Return:      TRUE if no error
ERR_UI_RES_NOT_FOUND
* Comment:     Won't re-draw the object for u
*********************************************************/
Err FieldDeleteString(ObjectID field_id, WORD start_char, WORD cut_length)
{
	Field *addr;
	BYTE object_type;
	WORD total_length, text_cont_text, add_length, i;
	
	if (UISearchForAddress(field_id,&object_type,(void**)&addr) != TRUE)
		return ERR_UI_RES_NOT_FOUND;
	
	if (cut_length < 0)
	{
		start_char += cut_length;
		cut_length = -cut_length;
	}
	
    total_length = strlen(addr->field_string) + 1;
	text_cont_text = start_char+cut_length;
	
	if (text_cont_text > total_length)
		add_length = 0;
	else
		add_length = total_length-text_cont_text;
	
	for (i=0; i< add_length; i++)
		addr->field_string[start_char++] = addr->field_string[text_cont_text++];
	
	addr->field_current_num_chars = strlen(addr->field_string);
	return TRUE;
}

/********************************************************
* Function: FieldCutBackspaceHighlightText
* Purpose:  Delete the specified range of characters from
the field and redraw the field
* Scope:	Application
* Input:	field_id		DBID of the spceified field object
* Output:	None
* Return:	None
* Comment:	None
**********************************************************/
void FieldCutBackspaceHighlightText(Field *addr)
{
	BYTE *text_pointer;
	WORD total_length, add_length, text_cont_text, i, count;
	WORD cut_start_char, cut_length;
	
	cut_start_char = addr->field_highlight_start_char;
	cut_length = addr->field_highlight_length;
	
	if (!addr->field_attr.field_drawn)
		StrAnalyzeLine(addr);
	if (addr->field_highlight_length < 0)
	{
		cut_start_char += addr->field_highlight_length;
		cut_length = abs(cut_length);
	}
    if (undo_buffer.clipboard_type == CLIP_TEXT_DATA)
    {
        undo_buffer.clipboard_type = CLIP_EMPTY;
        undo_buffer.clipboard_size = 0;
        qfree(undo_buffer.clipboard_data);
    }
    undo_buffer.clipboard_type = CLIP_TEXT_DATA;
    undo_buffer.clipboard_size = cut_length;
    undo_buffer.clipboard_data = (BYTE*)qmalloc((cut_length+1)*sizeof(BYTE));
    StrExtract(addr->field_string,cut_start_char,cut_length,(BYTE*)undo_buffer.clipboard_data);
	
	total_length = strlen(addr->field_string)+1;
	text_cont_text = cut_start_char + cut_length;
	add_length = total_length - text_cont_text;
	
	count = cut_start_char;
	
	for (i=0; i< add_length; i++)
	{
		addr->field_string[count] = addr->field_string[text_cont_text++];
		count++;
	}	
	
	addr->field_current_num_chars = strlen(addr->field_string);
	addr->field_attr.field_highlight == FALSE;
    undo_action = UNDO_BACKSPACE_HIGHLIGHT;
}
