/**************************************************************************/
/*                                                                        */
/*       Copyright (c) Microsoft Corporation. All rights reserved.        */
/*                                                                        */
/*       This software is licensed under the Microsoft Software License   */
/*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
/*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
/*       and in the root directory of this software.                      */
/*                                                                        */
/**************************************************************************/


/**************************************************************************/
/**************************************************************************/
/**                                                                       */
/** GUIX Component                                                        */
/**                                                                       */
/**   Text Input Management (Single Line Text Input)                      */
/**                                                                       */
/**************************************************************************/

#define GX_SOURCE_CODE


/* Include necessary system files.  */

#include "gx_api.h"
#include "gx_context.h"
#include "gx_system.h"
#include "gx_widget.h"
#include "gx_single_line_text_input.h"
#include "gx_utility.h"

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _gx_single_line_text_input_position_get             PORTABLE C      */
/*                                                           6.1          */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Kenneth Maxwell, Microsoft Corporation                              */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This service positions the text input cursor based on the requested */
/*    cursor position. The text input cursor index will be calculated     */
/*    based on the x value of the pixel pisition.                         */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    text_input                                Single-line text input    */
/*                                                widget control block    */
/*    pixel_position                            X value of pixel position */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    Status                                    Completion status         */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _gx_widget_font_get                   Get widget font               */
/*    _gx_widget_border_width_get           Get the widget border width   */
/*    _gx_widget_client_get                 Get client rectangle          */
/*    _gx_utility_utf8_string_character_get Parse utf8 string to          */
/*                                            multi-byte glyph            */
/*    _gx_system_string_width_get           Get the width of a string     */
/*    _gx_system_dirty_mark                 Mark a widget area dirty      */
/*    _gx_system_dirty_partial_add          Mark the partial area of a    */
/*                                            widget as dirty             */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    Application Code                                                    */
/*    GUIX Internal Code                                                  */
/*                                                                        */
/*  RELEASE HISTORY                                                       */
/*                                                                        */
/*    DATE              NAME                      DESCRIPTION             */
/*                                                                        */
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
/*                                            resulting in version 6.1    */
/*                                                                        */
/**************************************************************************/
UINT _gx_single_line_text_input_position_get(GX_SINGLE_LINE_TEXT_INPUT *text_input, INT pixel_position)
{
GX_TEXT_INPUT_CURSOR *cursor_ptr;
GX_CHAR              *string_buffer;
GX_FONT              *gx_font;
GX_RECTANGLE          client;
GX_VALUE              width;
GX_VALUE              cursor_pos;
GX_VALUE              x_pos;
GX_VALUE              distance;
UINT                  new_insert_pos;
UINT                  index;
UINT                  glyph_len = 1;
GX_STRING             utf8_string;
GX_STRING             string;

    string.gx_string_ptr = text_input -> gx_single_line_text_input_buffer;
    string.gx_string_length = text_input -> gx_single_line_text_input_string_size;

    cursor_ptr = &text_input -> gx_single_line_text_input_cursor_instance;

    string_buffer = text_input -> gx_single_line_text_input_buffer;

    _gx_widget_font_get((GX_WIDGET *)text_input, text_input -> gx_prompt_font_id, &gx_font);

    _gx_widget_border_width_get((GX_WIDGET *)text_input, &width);
    _gx_widget_client_get((GX_WIDGET *)text_input, width, &client);

    switch (text_input -> gx_widget_style & GX_STYLE_TEXT_ALIGNMENT_MASK)
    {
    case GX_STYLE_TEXT_RIGHT:
        x_pos = (GX_VALUE)(client.gx_rectangle_right - 1);
        break;

    case GX_STYLE_TEXT_CENTER:
        x_pos = (GX_VALUE)(client.gx_rectangle_left + 1 + ((client.gx_rectangle_right - client.gx_rectangle_left + 1) >> 1));
        break;

    case GX_STYLE_TEXT_LEFT:
    default:
        x_pos = (GX_VALUE)(client.gx_rectangle_left + 1);
        break;
    }

    x_pos = (GX_VALUE)(x_pos - text_input -> gx_single_line_text_input_xoffset);

    /* Reset mouse down position when it was out of the text show area. */
    if (pixel_position < client.gx_rectangle_left + 1)
    {
        pixel_position = client.gx_rectangle_left + 1;
    }
    else if (pixel_position > client.gx_rectangle_right + 1)
    {
        pixel_position = client.gx_rectangle_right - 1;
    }

    /*Compute the distance from the first character position to the mouse down position. */
    if (pixel_position > x_pos)
    {
        distance = (GX_VALUE)(pixel_position - x_pos);
    }
    else
    {
        distance = 0;
    }

    new_insert_pos = string.gx_string_length;
    index = 0;
    cursor_pos = 0;

    while (string.gx_string_length > 0)
    {
#ifdef GX_UTF8_SUPPORT
        _gx_utility_utf8_string_character_get(&string, GX_NULL, &glyph_len);
#else
        string.gx_string_ptr++;
        string.gx_string_length--;
#endif
        utf8_string.gx_string_ptr = string_buffer + index;
        utf8_string.gx_string_length = glyph_len;

        _gx_system_string_width_get_ext(gx_font, &utf8_string, &width);
        if ((cursor_pos + width / 2) > distance)
        {
            new_insert_pos = index;
            break;
        }
        cursor_pos = (GX_VALUE)(cursor_pos + width);
        index += glyph_len;
    }

    /* Update insert position. */
    text_input -> gx_single_line_text_input_insert_pos = new_insert_pos;

    cursor_pos = (GX_VALUE)(x_pos + cursor_pos);

    if (cursor_pos < client.gx_rectangle_left + 1)
    {
        /* Cursor is beyond widget left, adjust text offset to show cursor.  */
        cursor_ptr -> gx_text_input_cursor_pos.gx_point_x = (GX_VALUE)(client.gx_rectangle_left + 1);

        distance = (GX_VALUE)(client.gx_rectangle_left + 1 - cursor_pos);
        text_input -> gx_single_line_text_input_xoffset = (GX_VALUE)(text_input -> gx_single_line_text_input_xoffset - distance);

        /* Text offset is modified, mark whole text input area dirty. */
        _gx_system_dirty_mark((GX_WIDGET *)text_input);
    }
    else if (cursor_pos > client.gx_rectangle_right - 1)
    {
        /* Cursor is beyond widget right, adjust text offset to show cursor.  */
        cursor_ptr -> gx_text_input_cursor_pos.gx_point_x = (GX_VALUE)(client.gx_rectangle_right - 1);

        distance = (GX_VALUE)(cursor_pos - (client.gx_rectangle_right - 1));
        text_input -> gx_single_line_text_input_xoffset = (GX_VALUE)(text_input -> gx_single_line_text_input_xoffset + distance);

        /* Text offset is modified, mark whole text input area dirty. */
        _gx_system_dirty_mark((GX_WIDGET *)text_input);
    }
    else if (cursor_ptr -> gx_text_input_cursor_pos.gx_point_x != cursor_pos)
    {
        /* For this situation, we only need to mark old and new cursor position dirty.  */
        client.gx_rectangle_left = (GX_VALUE)(cursor_ptr -> gx_text_input_cursor_pos.gx_point_x - (cursor_ptr -> gx_text_input_cursor_width >> 1));
        client.gx_rectangle_right = (GX_VALUE)(client.gx_rectangle_left + cursor_ptr -> gx_text_input_cursor_width);
        _gx_system_dirty_partial_add((GX_WIDGET *)text_input, &client);

        cursor_ptr -> gx_text_input_cursor_pos.gx_point_x = cursor_pos;

        client.gx_rectangle_left = (GX_VALUE)(cursor_ptr -> gx_text_input_cursor_pos.gx_point_x - (cursor_ptr -> gx_text_input_cursor_width >> 1));
        client.gx_rectangle_right = (GX_VALUE)(client.gx_rectangle_left + cursor_ptr -> gx_text_input_cursor_width);
        _gx_system_dirty_partial_add((GX_WIDGET *)text_input, &client);
    }

    return GX_SUCCESS;
}