1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 
12 /**************************************************************************/
13 /**************************************************************************/
14 /**                                                                       */
15 /** GUIX Component                                                        */
16 /**                                                                       */
17 /**   Multi Line Text Input Management (Multi Line Text Input)            */
18 /**                                                                       */
19 /**************************************************************************/
20 
21 #define GX_SOURCE_CODE
22 
23 
24 /* Include necessary system files.  */
25 
26 #include "gx_api.h"
27 #include "gx_system.h"
28 #include "gx_window.h"
29 #include "gx_widget.h"
30 #include "gx_multi_line_text_input.h"
31 #include "gx_multi_line_text_view.h"
32 #include "gx_text_input_cursor.h"
33 
34 /**************************************************************************/
35 /*                                                                        */
36 /*  FUNCTION                                               RELEASE        */
37 /*                                                                        */
38 /*    _gx_multi_line_text_input_pen_down_process          PORTABLE C      */
39 /*                                                           6.1          */
40 /*  AUTHOR                                                                */
41 /*                                                                        */
42 /*    Kenneth Maxwell, Microsoft Corporation                              */
43 /*                                                                        */
44 /*  DESCRIPTION                                                           */
45 /*                                                                        */
46 /*    This function handles pen down event for multi line text input      */
47 /*    widget.                                                             */
48 /*                                                                        */
49 /*  INPUT                                                                 */
50 /*                                                                        */
51 /*    text_input                            Multi-line text input widget  */
52 /*                                            control block               */
53 /*    event_ptr                             Pointer to GX_EVENT structure */
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    status                                Completion status             */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    _gx_system_input_capture              Direct all input events to    */
62 /*                                            specified widget            */
63 /*    _gx_multi_line_text_input_highlight_rectangle_get                   */
64 /*                                          Retrieve rectangle of         */
65 /*                                            highlight text              */
66 /*    _gx_text_input_cursor_dirty_rectangle_get                           */
67 /*                                          Retrieve cursor rectangle     */
68 /*    _gx_multi_line_text_input_cursor_pos_calculate                      */
69 /*                                          Update text insert position   */
70 /*    _gx_system_dirty_partial_add          Mark the partial area of a    */
71 /*                                            widget as dirty             */
72 /*    _gx_system_dirty_mark                 Mark specified widget dirty   */
73 /*    _gx_window_event_process              Default window event process  */
74 /*                                                                        */
75 /*  CALLED BY                                                             */
76 /*                                                                        */
77 /*    _gx_multi_line_text_input_event_process                             */
78 /*                                                                        */
79 /*  RELEASE HISTORY                                                       */
80 /*                                                                        */
81 /*    DATE              NAME                      DESCRIPTION             */
82 /*                                                                        */
83 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
84 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
85 /*                                            resulting in version 6.1    */
86 /*                                                                        */
87 /**************************************************************************/
_gx_multi_line_text_input_pen_down_process(GX_MULTI_LINE_TEXT_INPUT * text_input,GX_EVENT * event_ptr)88 static UINT _gx_multi_line_text_input_pen_down_process(GX_MULTI_LINE_TEXT_INPUT *text_input, GX_EVENT *event_ptr)
89 {
90 GX_TEXT_INPUT_CURSOR *cursor_ptr = &text_input -> gx_multi_line_text_input_cursor_instance;
91 INT                   scroll_shift;
92 GX_RECTANGLE          cursor_rect;
93 UINT                  start_mark = text_input -> gx_multi_line_text_input_start_mark;
94 UINT                  end_mark = text_input -> gx_multi_line_text_input_end_mark;
95 
96     _gx_system_input_capture((GX_WIDGET *)text_input);
97 
98     scroll_shift = text_input -> gx_multi_line_text_view_text_scroll_shift;
99 
100     if (start_mark != end_mark)
101     {
102         _gx_multi_line_text_input_highlight_rectangle_get(text_input, &cursor_rect);
103     }
104     else
105     {
106         /* Record cursor rectangle and scroll shift value before recaculate cursor position. */
107         _gx_text_input_cursor_dirty_rectangle_get(cursor_ptr, &cursor_rect);
108     }
109 
110     /* Calculate cursor position according to click position. */
111     _gx_multi_line_text_input_cursor_pos_calculate(text_input, (*event_ptr).gx_event_payload.gx_event_pointdata);
112 
113     /* Set highlight start/end mark to insert position. */
114     text_input -> gx_multi_line_text_input_start_mark = text_input -> gx_multi_line_text_input_text_insert_position;
115     text_input -> gx_multi_line_text_input_end_mark = text_input -> gx_multi_line_text_input_text_insert_position;
116 
117     if (scroll_shift != text_input -> gx_multi_line_text_view_text_scroll_shift)
118     {
119         _gx_system_dirty_mark((GX_WIDGET *)text_input);
120     }
121     else
122     {
123         if (start_mark != end_mark)
124         {
125             /* Mark highlight area as dirty. */
126             _gx_system_dirty_partial_add((GX_WIDGET *)text_input, &cursor_rect);
127         }
128         else
129         {
130             _gx_system_dirty_partial_add((GX_WIDGET *)text_input, &cursor_rect);
131 
132             /* Get current cursor rectangle. */
133             _gx_text_input_cursor_dirty_rectangle_get(cursor_ptr, &cursor_rect);
134 
135             _gx_system_dirty_partial_add((GX_WIDGET *)text_input, &cursor_rect);
136         }
137     }
138 
139     return _gx_window_event_process((GX_WINDOW *)text_input, event_ptr);
140 }
141 
142 
143 /**************************************************************************/
144 /*                                                                        */
145 /*  FUNCTION                                               RELEASE        */
146 /*                                                                        */
147 /*    _gx_multi_line_text_input_pen_drag_process          PORTABLE C      */
148 /*                                                           6.1          */
149 /*  AUTHOR                                                                */
150 /*                                                                        */
151 /*    Kenneth Maxwell, Microsoft Corporation                              */
152 /*                                                                        */
153 /*  DESCRIPTION                                                           */
154 /*                                                                        */
155 /*    This function handles pen drag event for multi line text input      */
156 /*    widget.                                                             */
157 /*                                                                        */
158 /*  INPUT                                                                 */
159 /*                                                                        */
160 /*    text_input                            Multi-line text input widget  */
161 /*                                            control block               */
162 /*    event_ptr                             Pointer to GX_EVENT structure */
163 /*                                                                        */
164 /*  OUTPUT                                                                */
165 /*                                                                        */
166 /*    status                                Completion status             */
167 /*                                                                        */
168 /*  CALLS                                                                 */
169 /*                                                                        */
170 /*    _gx_text_input_cursor_dirty_rectangle_get                           */
171 /*                                          Retrieve cursor rectangle     */
172 /*    _gx_multi_line_text_input_text_rectangle_get                        */
173 /*                                          Retrieve text rectangle       */
174 /*                                            between specified position  */
175 /*    _gx_multi_line_text_input_cursor_pos_calculate                      */
176 /*                                          Update text insert position   */
177 /*    _gx_system_dirty_partial_add          Mark the partial area of a    */
178 /*                                            widget as dirty             */
179 /*    _gx_system_timer_start                Start a timer                 */
180 /*    _gx_system_timer_stop                 Stop a timer                  */
181 /*    _gx_windwo_event_process              Default window event process  */
182 /*                                                                        */
183 /*  CALLED BY                                                             */
184 /*                                                                        */
185 /*    _gx_multi_line_text_input_event_process                             */
186 /*                                                                        */
187 /*  RELEASE HISTORY                                                       */
188 /*                                                                        */
189 /*    DATE              NAME                      DESCRIPTION             */
190 /*                                                                        */
191 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
192 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
193 /*                                            resulting in version 6.1    */
194 /*                                                                        */
195 /**************************************************************************/
_gx_multi_line_text_input_pen_drag_process(GX_MULTI_LINE_TEXT_INPUT * text_input,GX_EVENT * event_ptr)196 static UINT _gx_multi_line_text_input_pen_drag_process(GX_MULTI_LINE_TEXT_INPUT *text_input, GX_EVENT *event_ptr)
197 {
198 GX_TEXT_INPUT_CURSOR *cursor_ptr = &text_input -> gx_multi_line_text_input_cursor_instance;
199 INT                   scroll_shift;
200 GX_RECTANGLE          cursor_rect;
201 GX_POINT              start_pos;
202 UINT                  old_end_mark;
203 GX_RECTANGLE          client;
204 GX_POINT              click_pos;
205 GX_VALUE              click_y;
206 
207     if (text_input -> gx_widget_status & GX_STATUS_OWNS_INPUT)
208     {
209         client = text_input -> gx_window_client;
210 
211         click_pos = event_ptr -> gx_event_payload.gx_event_pointdata;
212         click_y = click_pos.gx_point_y;
213 
214         if (text_input -> gx_multi_line_text_input_start_mark == text_input -> gx_multi_line_text_input_end_mark)
215         {
216             _gx_text_input_cursor_dirty_rectangle_get(cursor_ptr, &cursor_rect);
217 
218             /* Mark cursor area as dirty. */
219             _gx_system_dirty_partial_add((GX_WIDGET *)text_input, &cursor_rect);
220         }
221 
222         start_pos = cursor_ptr -> gx_text_input_cursor_pos;
223 
224         scroll_shift = text_input -> gx_multi_line_text_view_text_scroll_shift;
225         old_end_mark = text_input -> gx_multi_line_text_input_end_mark;
226 
227         if (click_pos.gx_point_y < client.gx_rectangle_top)
228         {
229             click_pos.gx_point_y = client.gx_rectangle_top;
230         }
231         else if (click_pos.gx_point_y > client.gx_rectangle_bottom)
232         {
233             click_pos.gx_point_y = client.gx_rectangle_bottom;
234         }
235         _gx_multi_line_text_input_cursor_pos_calculate(text_input, click_pos);
236 
237         text_input -> gx_multi_line_text_input_end_mark = text_input -> gx_multi_line_text_input_text_insert_position;
238 
239         if ((click_y < client.gx_rectangle_top) &&
240             (text_input -> gx_multi_line_text_input_text_cursor_line > 1))
241         {
242             if (!(text_input -> gx_widget_status & (GX_STATUS_MARK_NEXT | GX_STATUS_MARK_PREVIOUS)))
243             {
244                 /* Start a timer to move text right. */
245                 _gx_system_timer_start((GX_WIDGET *)text_input, GX_MARK_TIMER,
246                                        GX_MARK_INTERVAL, GX_MARK_INTERVAL);
247             }
248 
249             text_input -> gx_widget_status &= ~GX_STATUS_MARK_NEXT;
250             text_input -> gx_widget_status |= GX_STATUS_MARK_PREVIOUS;
251         }
252         else if ((click_y > client.gx_rectangle_bottom) &&
253                  (text_input -> gx_multi_line_text_input_text_cursor_line < text_input -> gx_multi_line_text_view_text_total_rows))
254         {
255             if (!(text_input -> gx_widget_status & (GX_STATUS_MARK_NEXT | GX_STATUS_MARK_PREVIOUS)))
256             {
257                 /* Start a timer to move text left. */
258                 _gx_system_timer_start((GX_WIDGET *)text_input, GX_MARK_TIMER,
259                                        GX_MARK_INTERVAL, GX_MARK_INTERVAL);
260             }
261 
262             text_input -> gx_widget_status &= ~GX_STATUS_MARK_PREVIOUS;
263             text_input -> gx_widget_status |= GX_STATUS_MARK_NEXT;
264         }
265         else
266         {
267             if (text_input -> gx_widget_status & (GX_STATUS_MARK_NEXT | GX_STATUS_MARK_PREVIOUS))
268             {
269                 _gx_system_timer_stop((GX_WIDGET *)text_input, GX_MARK_TIMER);
270                 text_input -> gx_widget_status &= ~(GX_STATUS_MARK_NEXT | GX_STATUS_MARK_PREVIOUS);
271             }
272         }
273 
274         if (scroll_shift != text_input -> gx_multi_line_text_view_text_scroll_shift)
275         {
276             _gx_system_dirty_mark((GX_WIDGET *)text_input);
277         }
278         else
279         {
280             if ((text_input -> gx_multi_line_text_input_start_mark != text_input -> gx_multi_line_text_input_end_mark) ||
281                 (text_input -> gx_multi_line_text_input_start_mark != old_end_mark))
282             {
283                 _gx_multi_line_text_input_text_rectangle_get(text_input,
284                                                              start_pos,
285                                                              cursor_ptr -> gx_text_input_cursor_pos, &cursor_rect);
286 
287                 /* Mark highlight area as dirty. */
288                 _gx_system_dirty_partial_add((GX_WIDGET *)text_input, &cursor_rect);
289             }
290         }
291     }
292     else
293     {
294         _gx_window_event_process((GX_WINDOW *)text_input, event_ptr);
295     }
296 
297     return GX_SUCCESS;
298 }
299 
300 /**************************************************************************/
301 /*                                                                        */
302 /*  FUNCTION                                               RELEASE        */
303 /*                                                                        */
304 /*    _gx_multi_line_text_input_event_process             PORTABLE C      */
305 /*                                                           6.1.3        */
306 /*  AUTHOR                                                                */
307 /*                                                                        */
308 /*    Kenneth Maxwell, Microsoft Corporation                              */
309 /*                                                                        */
310 /*  DESCRIPTION                                                           */
311 /*                                                                        */
312 /*    This function processes events for the specified text input widget. */
313 /*                                                                        */
314 /*  INPUT                                                                 */
315 /*                                                                        */
316 /*    text_input                            Multi line text input         */
317 /*                                            control block               */
318 /*    event_ptr                             Incoming event to process     */
319 /*                                                                        */
320 /*  OUTPUT                                                                */
321 /*                                                                        */
322 /*    status                                Completion status             */
323 /*                                                                        */
324 /*  CALLS                                                                 */
325 /*                                                                        */
326 /*    _gx_widget_event_process              Default widget event process  */
327 /*    _gx_system_timer_start                Allocate a free timer and     */
328 /*                                          activates it                  */
329 /*    _gx_system_timer_stop                 Stop an active GUIX timer     */
330 /*    _gx_multi_line_text_input_keydown_process                           */
331 /*                                          Process the keydown event     */
332 /*    _gx_widget_event_generate             Generate an event             */
333 /*    _gx_text_input_cursor_dirty_rectangle_get                           */
334 /*                                          Get cursor rectangle          */
335 /*    _gx_multi_line_text_input_cursor_pos_calculate                      */
336 /*                                          Calculate cursor position     */
337 /*                                            according to click positin  */
338 /*    _gx_multi_line_text_input_cursor_pos_update                         */
339 /*                                          Update cursor position        */
340 /*                                            according to insert position*/
341 /*    _gx_system_dirty_partial_add          Add a dirty area to the       */
342 /*                                            specified widget            */
343 /*    _gx_multi_line_text_view_event_process                              */
344 /*                                          Invoke the text view event    */
345 /*                                            process routine             */
346 /*                                                                        */
347 /*  CALLED BY                                                             */
348 /*                                                                        */
349 /*    Application Code                                                    */
350 /*    GUIX Internal Code                                                  */
351 /*                                                                        */
352 /*  RELEASE HISTORY                                                       */
353 /*                                                                        */
354 /*    DATE              NAME                      DESCRIPTION             */
355 /*                                                                        */
356 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
357 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
358 /*                                            resulting in version 6.1    */
359 /*  12-31-2020     Kenneth Maxwell          Modified comment(s),          */
360 /*                                            added logic to release      */
361 /*                                            dynamic input buffer,       */
362 /*                                            resulting in version 6.1.3  */
363 /*                                                                        */
364 /**************************************************************************/
_gx_multi_line_text_input_event_process(GX_MULTI_LINE_TEXT_INPUT * text_input,GX_EVENT * event_ptr)365 UINT  _gx_multi_line_text_input_event_process(GX_MULTI_LINE_TEXT_INPUT *text_input, GX_EVENT *event_ptr)
366 {
367 GX_TEXT_INPUT_CURSOR    *cursor_ptr = &text_input -> gx_multi_line_text_input_cursor_instance;
368 GX_MULTI_LINE_TEXT_VIEW *view = (GX_MULTI_LINE_TEXT_VIEW *)text_input;
369 GX_WIDGET               *widget = (GX_WIDGET *)text_input;
370 GX_VALUE                 blink_interval = text_input -> gx_multi_line_text_input_cursor_instance.gx_text_input_cursor_blink_interval;
371 UINT                     status;
372 GX_RECTANGLE             cursor_rect;
373 INT                      scroll_shift;
374 ULONG                    old_style;
375 
376     /* Default status to success.  */
377     status =  GX_SUCCESS;
378 
379     /* Process relative to the type of event.  */
380     switch (event_ptr -> gx_event_type)
381     {
382     case GX_EVENT_SHOW:
383         _gx_window_event_process((GX_WINDOW *)text_input, event_ptr);
384 
385         /* Update cursor position. */
386         _gx_multi_line_text_input_cursor_pos_update(text_input, GX_TRUE);
387 
388         if ((text_input -> gx_widget_style & GX_STYLE_CURSOR_ALWAYS) &&
389             (text_input -> gx_widget_style & GX_STYLE_CURSOR_BLINK))
390         {
391             /* Start the timer.  */
392             _gx_system_timer_start(widget, ID_TEXT_INPUT_TIMER, GX_CURSOR_BLINK_INTERVAL, GX_CURSOR_BLINK_INTERVAL);
393         }
394 
395         /* Get visible rows. */
396         _gx_multi_line_text_view_visible_rows_compute((GX_MULTI_LINE_TEXT_VIEW *)text_input);
397         break;
398 
399     case GX_EVENT_STYLE_CHANGED:
400         if (widget -> gx_widget_status & GX_STATUS_VISIBLE)
401         {
402             _gx_multi_line_text_view_event_process((GX_MULTI_LINE_TEXT_VIEW *)text_input, event_ptr);
403 
404             old_style = event_ptr -> gx_event_payload.gx_event_ulongdata;
405             if ((old_style & (GX_STYLE_BORDER_MASK | GX_STYLE_TEXT_ALIGNMENT_MASK)) !=
406                 (widget -> gx_widget_style & (GX_STYLE_BORDER_MASK | GX_STYLE_TEXT_ALIGNMENT_MASK)))
407             {
408                 text_input -> gx_multi_line_text_view_line_index_old = GX_TRUE;
409             }
410         }
411         break;
412 
413     case GX_EVENT_FOCUS_GAINED:
414         /* Call the widget default processing. */
415         _gx_widget_event_process(widget, event_ptr);
416 
417         /* Do not do anything if the CURSOR_ALWAYS flag is set. */
418         if (!(text_input -> gx_widget_style & GX_STYLE_CURSOR_ALWAYS))
419         {
420             text_input -> gx_widget_status |= (GX_STATUS_CURSOR_SHOW | GX_STATUS_CURSOR_DRAW);
421 
422             if (text_input -> gx_widget_style & GX_STYLE_CURSOR_BLINK)
423             {
424                 /* Start the timer.  */
425                 _gx_system_timer_start(widget, ID_TEXT_INPUT_TIMER, (UINT)blink_interval, (UINT)blink_interval);
426             }
427         }
428 
429         _gx_multi_line_text_input_text_select(text_input, 0, text_input -> gx_multi_line_text_view_text.gx_string_length - 1);
430         break;
431 
432     case GX_EVENT_KEY_DOWN:
433         _gx_multi_line_text_input_keydown_process(text_input, event_ptr);
434         if (widget -> gx_widget_style & GX_STYLE_TEXT_INPUT_NOTIFY_ALL)
435         {
436             _gx_widget_event_generate(widget, GX_EVENT_TEXT_EDITED, 0);
437         }
438         break;
439 
440     case GX_EVENT_PEN_DOWN:
441         _gx_multi_line_text_input_pen_down_process(text_input, event_ptr);
442         break;
443 
444     case GX_EVENT_PEN_DRAG:
445         _gx_multi_line_text_input_pen_drag_process(text_input, event_ptr);
446         break;
447 
448     case GX_EVENT_PEN_UP:
449         if (text_input -> gx_widget_status & GX_STATUS_OWNS_INPUT)
450         {
451             _gx_system_input_release((GX_WIDGET *)text_input);
452 
453             if (text_input -> gx_widget_status & (GX_STATUS_MARK_NEXT | GX_STATUS_MARK_PREVIOUS))
454             {
455                 _gx_system_timer_stop((GX_WIDGET *)text_input, GX_MARK_TIMER);
456                 text_input -> gx_widget_status &= ~(GX_STATUS_MARK_NEXT | GX_STATUS_MARK_PREVIOUS);
457             }
458         }
459         else
460         {
461             _gx_window_event_process((GX_WINDOW *)text_input, event_ptr);
462         }
463         break;
464 
465     case GX_EVENT_TIMER:
466         if (event_ptr -> gx_event_payload.gx_event_timer_id == GX_MARK_TIMER)
467         {
468             if (text_input -> gx_widget_status & GX_STATUS_MARK_PREVIOUS)
469             {
470                 _gx_multi_line_text_input_mark_up(text_input);
471             }
472             else
473             {
474                 _gx_multi_line_text_input_mark_down(text_input);
475             }
476         }
477         else if ((event_ptr -> gx_event_payload.gx_event_timer_id == ID_TEXT_INPUT_TIMER) &&
478                  (text_input -> gx_widget_status & GX_STATUS_CURSOR_SHOW) &&
479                  (text_input -> gx_multi_line_text_input_start_mark == text_input -> gx_multi_line_text_input_end_mark))
480         {
481             if (text_input -> gx_widget_status & GX_STATUS_CURSOR_DRAW)
482             {
483                 text_input -> gx_widget_status &= (ULONG)(~GX_STATUS_CURSOR_DRAW);
484             }
485             else
486             {
487                 text_input -> gx_widget_status |= GX_STATUS_CURSOR_DRAW;
488             }
489             /* Define a cursor rectangle for the cursor. */
490             _gx_text_input_cursor_dirty_rectangle_get(&text_input -> gx_multi_line_text_input_cursor_instance, &cursor_rect);
491             _gx_system_dirty_partial_add(widget, &cursor_rect);
492         }
493         break;
494 
495     case GX_EVENT_FOCUS_LOST:
496         _gx_widget_event_process(widget, event_ptr);
497 
498         /* Do not do anything if the CURSOR_ALWAYS flag is set. */
499         if (!(text_input -> gx_widget_style & GX_STYLE_CURSOR_ALWAYS))
500         {
501             text_input ->  gx_widget_status &= (ULONG)(~GX_STATUS_CURSOR_SHOW);
502 
503             /* Stop the timer if the cursor style is BLINK. */
504             if (text_input -> gx_widget_style & GX_STYLE_CURSOR_BLINK)
505             {
506                 /* Stop the timer. */
507                 _gx_system_timer_stop(widget, 0);
508             }
509 
510             /* Define a cursor rectangle for the cursor. */
511             _gx_text_input_cursor_dirty_rectangle_get(&text_input -> gx_multi_line_text_input_cursor_instance, &cursor_rect);
512             _gx_system_dirty_partial_add(widget, &cursor_rect);
513         }
514 
515         if (text_input -> gx_multi_line_text_input_start_mark != text_input -> gx_multi_line_text_input_end_mark)
516         {
517             _gx_multi_line_text_input_highlight_rectangle_get(text_input, &cursor_rect);
518 
519             text_input -> gx_multi_line_text_input_start_mark = 0;
520             text_input -> gx_multi_line_text_input_end_mark = 0;
521 
522             _gx_system_dirty_partial_add(widget, &cursor_rect);
523         }
524 
525         if (text_input -> gx_multi_line_text_input_text_was_modified)
526         {
527             _gx_widget_event_generate(widget, GX_EVENT_TEXT_EDITED, 0);
528             text_input -> gx_multi_line_text_input_text_was_modified = GX_FALSE;
529         }
530         break;
531 
532     case GX_EVENT_VERTICAL_SCROLL:
533         /* Pick up scroll shift value. */
534         scroll_shift = event_ptr -> gx_event_payload.gx_event_intdata[1] - event_ptr -> gx_event_payload.gx_event_intdata[0];
535 
536         /* Move cursor position according to shift value. */
537         cursor_ptr -> gx_text_input_cursor_pos.gx_point_y = (GX_VALUE)(cursor_ptr -> gx_text_input_cursor_pos.gx_point_y + scroll_shift);
538 
539         /* Call the multi-line text view event processing. */
540         _gx_multi_line_text_view_event_process(view, event_ptr);
541         break;
542 
543     case GX_EVENT_LANGUAGE_CHANGE:
544         break;
545 
546     case GX_EVENT_COPY:
547         _gx_multi_line_text_input_copy(text_input);
548         break;
549 
550     case GX_EVENT_CUT:
551         _gx_multi_line_text_input_cut(text_input);
552         break;
553 
554     case GX_EVENT_PASTE:
555         _gx_multi_line_text_input_paste(text_input);
556         break;
557 
558     case GX_EVENT_MARK_NEXT:
559         _gx_multi_line_text_input_mark_next(text_input);
560         break;
561 
562     case GX_EVENT_MARK_PREVIOUS:
563         _gx_multi_line_text_input_mark_previous(text_input);
564         break;
565 
566     case GX_EVENT_MARK_UP:
567         _gx_multi_line_text_input_mark_up(text_input);
568         break;
569 
570     case GX_EVENT_MARK_DOWN:
571         _gx_multi_line_text_input_mark_down(text_input);
572         break;
573 
574     case GX_EVENT_MARK_END:
575         _gx_multi_line_text_input_mark_end(text_input);
576         break;
577 
578     case GX_EVENT_MARK_HOME:
579         _gx_multi_line_text_input_mark_home(text_input);
580         break;
581 
582     case GX_EVENT_DELETE:
583         if (text_input -> gx_widget_status & GX_STATUS_DYNAMIC_BUFFER)
584         {
585             if (!_gx_system_memory_free)
586             {
587                 return GX_SYSTEM_MEMORY_ERROR;
588             }
589 
590             _gx_system_memory_free((void *)text_input -> gx_multi_line_text_view_text.gx_string_ptr);
591             text_input -> gx_multi_line_text_view_text.gx_string_ptr = GX_NULL;
592         }
593         break;
594 
595     default:
596         /* Call the multi-line text view event processing.  */
597         status = _gx_multi_line_text_view_event_process(view, event_ptr);
598     }
599 
600     /* Return completion status.  */
601     return(status);
602 }
603 
604